51nod 更难的矩阵取数问题(动态规划)
更难的矩阵取数问题
给定一个m行n列的矩阵,矩阵每个元素是一个正整数,你现在 在左上角(第一行第一列),你需要走到右下角(第m行,第n列),每次只能朝右或者下走到相邻的位置,不能走出矩阵。然后再从右下角返回到左上角,这时只 能朝上或者左走,两次如果经过同一个格子,则该数字只计算一次,所有走过的数的总和作为你的得分,求最大的得分。
输入
第1行:2个数M N,中间用空格分隔,为矩阵的大小。(2 <= M, N <= 200) 第2 - N + 1行:每行M个数,中间用空格隔开,对应格子中奖励的价值。(1 <= A[i,j] <= 10000)
输出
输出能够获得的最大价值。
输入示例
3 3 1 3 3 2 1 3 2 2 1
输出示例
17
请选取你熟悉的语言,并在下面的代码框中完成你的程序,注意数据范围,最终结果会造成Int32溢出,这样会输出错误的答案。
不同语言如何处理输入输出,请查看下面的语言说明。
【分析】
没招了么?其实我们可以“两个人一起”dp(让两个人同时走)。
用dp[x1][y1][x2][y2]表示第一个人在(x1,y1) 并且第二个人在(x2,y2)时的最大值。
我们有初值dp[1][1][1][1] = a[1][1], 求的是dp[m][n][m][n]。
问题来了: 每个人走一步,状态转移是什么?
dp[x1][y1][x2][y2] = max{dp[x1’][y1’][x2’][y2’]} + a[x1][y1] + a[x2][y2]
其中(x1’,y1’)是(x1,y1)的邻居,(x2’,y2’)是(x2,y2)的邻居。
事实上,因为我们有这个等式提示我们其实只要用3维就可以表示这个矩阵,因为 y2 = x1 + y1 – x2所以那一维可以用走多少步表示出来。
View Code
用dp[x1][y1][x2][y2]表示第一个人在(x1,y1) 并且第二个人在(x2,y2)时的最大值。
我们有初值dp[1][1][1][1] = a[1][1], 求的是dp[m][n][m][n]。
问题来了: 每个人走一步,状态转移是什么?
dp[x1][y1][x2][y2] = max{dp[x1’][y1’][x2’][y2’]} + a[x1][y1] + a[x2][y2]
其中(x1’,y1’)是(x1,y1)的邻居,(x2’,y2’)是(x2,y2)的邻居。
事实上,因为我们有这个等式提示我们其实只要用3维就可以表示这个矩阵,因为 y2 = x1 + y1 – x2所以那一维可以用走多少步表示出来。
dp[step + 1][x1][x2] = max{dp[step][x1’][x2’]} + a[x1][y1] + a[x2][y2]
图中为step做了编号。
然而这个dp并没有体现出走到相同格子,数字仅计算一次的要求。那么我们加上这个条件:如果x1 = x2,dp[step + 1][x1][x2] = max{dp[step][x1’][x2’]} + a[x1][y1]。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> #include <climits> #include <cstring> #include <string> #include <set> #include <map> #include <queue> #include <stack> #include <vector> #include <list> #define inf 0x3f3f3f3f typedef long long ll; using namespace std ; #define inf 0x3f3f3f3f #define maxn 201 int M[maxn][maxn]; int dp[maxn<<1][maxn][maxn]; int main() { int n,m,i,j,x1,x2; scanf("%d%d",&m,&n); for(i=1;i<=n;++i) for(j=1;j<=m;++j) scanf("%d",&M[i][j]); memset(dp,0,sizeof(dp)); for(i=1;i<n+m;++i) for(x1=1;x1<=n&&i-x1>=0;++x1) for(x2=1;x2<=n&&i-x2>=0;++x2) { dp[i][x1][x2]=max(dp[i][x1][x2],dp[i-1][x1-1][x2-1]+M[x1][i-x1+1]+(x1==x2?0:M[x2][i-x2+1])); dp[i][x1][x2]=max(dp[i][x1][x2],dp[i-1][x1-1][x2]+M[x1][i-x1+1]+(x1==x2?0:M[x2][i-x2+1])); dp[i][x1][x2]=max(dp[i][x1][x2],dp[i-1][x1][x2-1]+M[x1][i-x1+1]+(x1==x2?0:M[x2][i-x2+1])); dp[i][x1][x2]=max(dp[i][x1][x2],dp[i-1][x1][x2]+M[x1][i-x1+1]+(x1==x2?0:M[x2][i-x2+1])); //printf("dp[%d][%d][%d]=%d\n",i,x1,x2,dp[i][x1][x2]); } printf("%d\n",dp[n+m-1][n][n]); return 0; }