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所以那一维可以用走多少步表示出来。
 
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
",i,x1,x2,dp[i][x1][x2]);
            }
    printf("%d
",dp[n+m-1][n][n]);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/jianrenfang/p/5709132.html