51Nod 1084 DP+滚动数组

来源:互联网 发布:手机免费淘宝p图软件 编辑:程序博客网 时间:2024/06/03 08:22

题目链接


题意:(经转化)
有一个nm的矩阵,两个人同时从最左上角的格子(0,0)出发,走到最右下角的格子(n1,m1),两个人每个时刻都都只能选择向下或者向右走一个格子,其中,每一个格子上面都有一个数字,问所有被经过的格子上的数字和最大可以是多少。(一个格子被两个人经过只计算一次贡献)

思路:
类似于CF上的某一道E
考虑动态规划

定义dp[t][i][j]t时刻,第一个人的横坐标为i,第二个人的横坐标为j时可以得到的最大值。

因每个时刻只有两个固定的方向,故横纵坐标之和一定等于时刻t。
故第一个人的坐标为(i,ti)
第二个人的坐标为(j,tj)

因为对于第一个人,前一个状态有两种可能,第二个人也是一样。故一共有四个转移方程。取maxdp[t1][i][j],dp[t1][i1][j]dp[t1][i][j1],dp[t1][i1][j1]+Add

因为两个人同时出发,一个点被两个人经过的时刻一定相同,故
i==j,Add为(i,t-i)点的值
否则,Add为(i,t-i)和(j,t-j)两个点的值的和。

又因为每一个时刻的状态只与上一个时刻有关,故第一维可以滚动优化。

代码:

#include<cstdio>#include<algorithm>using namespace std;const int A = 200 + 10;int dp[2][A][A],maze[A][A];int n,m;int main(){    scanf("%d%d",&m,&n);    for(int i=0 ;i<n ;i++)        for(int j=0 ;j<m ;j++) scanf("%d",&maze[i][j]);    dp[0][0][0] = maze[0][0];    for(int t=1 ;t<=n+m-2 ;t++){        int now = t&1;        for(int i=0 ;i<n ;i++){            int x1 = i,y1 = t-i;            if(x1<0 || x1>=n || y1<0 || y1>=m) continue;            for(int j=i ;j<n ;j++){                int x2 = j,y2 = t-j;                if(x2<0 || x2>=n || y2<0 || y2>=m) continue;                int add = 0;                if(x1 == x2) add = maze[x1][y1];                else         add = maze[x1][y1] + maze[x2][y2];                dp[now][x1][x2] = max(dp[now][x1][x2],dp[now^1][x1][x2] + add);                if(x1>0) dp[now][x1][x2] = max(dp[now][x1][x2],dp[now^1][x1-1][x2] + add);                if(x2>0) dp[now][x1][x2] = max(dp[now][x1][x2],dp[now^1][x1][x2-1] + add);                if(x1>0 && x2>0) dp[now][x1][x2] = max(dp[now][x1][x2],dp[now^1][x1-1][x2-1] + add);            }        }    }    printf("%d\n",dp[(n+m-2)&1][n-1][n-1]);    return 0;}