做标书要不要做网站,app项目开发流程,高新网站建设哪家好,怎么做网站一个平台取数字问题取数字问题取数字问题
Description
给定M*N的矩阵#xff0c;其中的每个元素都是-10到10之间的整数。你的任务是从左上角#xff08;1#xff0c;1#xff09;走到右下角#xff08;M#xff0c;N#xff09;#xff0c;每一步只能向右或向下#xff0c;并…取数字问题取数字问题取数字问题
Description
给定M*N的矩阵其中的每个元素都是-10到10之间的整数。你的任务是从左上角11走到右下角MN每一步只能向右或向下并且不能走出矩阵的范围。你所经过的方格里面的数字都必须被选取请找出一条最合适的道路使得在路上被选取的数字之和是尽可能小的正整数。
Input
第一行两个整数MN2M,N10分别表示矩阵的行和列的数目。
接下来的M行每行包括N个整数就是矩阵中的每一行的N个元素。
Output
仅一行一个整数表示所选道路上数字之和所能达到的最小的正整数。如果不能达到任何正整数就输出-1。
Sample Input
2 2
0 2
1 0
Sample Output
1
题目大意
有一个n*m的矩阵每个位置都有一个-10~10的分数每走到一个位置就会自动得到当前位置的分数要从11走到n,m要使分数是正整数并且最小若结果都非正整数输出-1
方法一方法一方法一
解题方法
先枚举一个i结果然后从(n,m)dfs到(1,1)使当前值为上一个f存结果减去当前的a本来的数值当(1,1)为0时就是可以从(n,m)到(1,1)否则枚举下一个a因为有负数所以存的时候要加一个M(我写的是1001)
#includeiostream
#includecstdio
#includecstring
#includealgorithm
#includestring
#define M 1001
using namespace std;
int ans,n,m,a[15][15],f[15][15][M*2];
void dfs(int x,int y,int d)//x,y为行列,d为当前数
{f[x][y][dM]1;if (f[1][1][M]) return;if ((x1)(!f[x-1][y][d-a[x-1][y]M])) dfs(x-1,y,d-a[x-1][y]);//往上要先判断是否越界是否走过同样的数如果走了同样的数就会浪费时间if ((y1)(!f[x][y-1][d-a[x][y-1]M])) dfs(x,y-1,d-a[x][y-1]);//往左要先判断是否越界是否走过同样的数如果走了同样的数就会浪费时间
}
int main()
{ans-1;scanf(%d%d,n,m);for (int i1;in;i)for (int j1;jm;j)scanf(%d,a[i][j]);//输入for (int i1;in*m*10;i)//枚举结果{dfs(n,m,i-a[n][m]);//最后一个要先减去它的a值if (f[1][1][M]) //如果有结果就记录break{ansi;break;}}printf(%d,ans);
}方法二方法二方法二
用DP的方法用一个数组f[i][j][k]来表示第i行第j列是否能得到数字k但k是已经加了一个M我写的是1001的所以在输出时要从M1开始
动态转移方程
{if(f[i−1][j][k])f[i][j][ka[i][j]]1if(f[i][j−1][k])f[i][j][ka[i][j]]1\left\{\begin{matrix}if(f[i-1][j][k]) f[i][j][ka[i][j]]1\\ if (f[i][j-1][k]) f[i][j][ka[i][j]]1\end{matrix}\right.{if(f[i−1][j][k])if(f[i][j−1][k])f[i][j][ka[i][j]]1f[i][j][ka[i][j]]1
解释
第一行的为取上的数第二行的为取上的数
程序解析待续…
#includecstdio
#includeiostream
#includecstring
#includestring
#define M 1001
using namespace std;
int a[15][15],f[15][15][M*25],n,m,t;
int main()
{scanf(%d%d,n,m);for (int i1;in;i)for (int j1;jm;j)scanf(%d,a[i][j]);f[1][1][a[1][1]M]1;//11的值初始化为自己的值ta[1][1]M;//存好后面要用for (int i2;in;i)//第一列下去f[i][1][ta[i][1]]1,ta[i][1];//t为前面的值加上当前的值再赋值1表示有这个数后面一句是为了方便后面求值ta[1][1]M;//再存后面还要用for (int j2;jm;j)//第一行f[1][j][ta[1][j]]1,ta[1][j];//同上for (int i2;in;i)//行for (int j2;jm;j)//列for (int k1;kM*2;k)//上一个的数字{if (f[i-1][j][k]) f[i][j][ka[i][j]]1;//动态转移方程if (f[i][j-1][k]) f[i][j][ka[i][j]]1;//动态转移方程}int kM1;//因0~M-1是负数M是0提前加过了所以从M1开始while ((!f[n][m][k])(kM*2)) k;//求最小第二个判定是为了不出界if (kM*2) printf(%d,k-M);//如果大于M*2就说明无解else printf(-1);
}方法三方法三方法三
直接相加用一个三位数组ff[i][j][0]表示第i行第j列有多少个数字之后的f[i][j][k]表示他的数字
#includecstdio
#includeiostream
#includecstring
using namespace std;
int a[11][11],n,m,ans,f[11][11][50000];
int main()
{scanf(%d%d,n,m);for (int i1;in;i)for (int j1;jm;j)scanf(%d,a[i][j]);f[1][1][0]1;//初始化f[1][1][1]a[1][1];//初始化for (int i2;in;i)f[i][1][1]f[i-1][1][1]a[i][1],f[i][1][0]1;//第一列for (int i2;im;i)f[1][i][1]f[1][i-1][1]a[1][i],f[1][i][0]1;//第一行for (int i2;in;i)for (int j2;jm;j){f[i][j][0]f[i-1][j][0]f[i][j-1][0];//数字个数为上面数字个数加左边数字个数for (int k1;kf[i-1][j][0];k)f[i][j][k]f[i-1][j][k]a[i][j];//直接加for (int k1;kf[i][j-1][0];k)f[i][j][kf[i-1][j][0]]f[i][j-1][k]a[i][j];//不能覆盖要再加上f[i-1][j][0]}ans2147483647;//因为要求最小所以要赋一个大的值for (int i1;if[n][m][0];i)if (f[n][m][i]0)//排除负数和0ansmin(ans,f[n][m][i]);if (ans2147483647) printf(-1);//如果没有改变输出-1else printf(%d,ans);
}