CH5103 [NOIP2008]传纸条[线性DP]

给定一个 N*M 的矩阵A,每个格子中有一个整数。现在需要找到两条从左上角 (1,1) 到右下角 (N,M) 的路径,路径上的每一步只能向右或向下走。路径经过的格子中的数会被取走。两条路径不能经过同一个格子。求取得的数之和最大是多少。N,M≤50。


由于走两条路径,可以直接把两个人未知设计入状态中。$f[x1][y1][x2][y2]$表示两个人分别所在处时最大价值。枚举两个人位置(或者,枚举第一个人所在位置,和第二个人所在行,其列也就由路径步数相等推出来了),每种状态分别由之前2*2四个方向转移即可。

我code可能有bug。。因为这题觉得简单没花太多时间考虑细节。

 1 #include
 2 #include
 3 #include
 4 #include
 5 #include
 6 #include
 7 #define dbg(x) cerr<<#x<<" = "< 8 #define ddbg(x,y) cerr<<#x<<" = "< 9 using namespace std;
10 typedef long long ll;
11 templateinline char MIN(T&A,T B){return A>B?A=B,1:0;}
12 templateinline char MAX(T&A,T B){return A1:0;}
13 templateinline T _min(T A,T B){return AA:B;}
14 templateinline T _max(T A,T B){return A>B?A:B;}
15 templateinline T read(T&x){
16     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
17     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
18 }
19 const int N=50+2;
20 int f[N][N][N][N],dis[N][N],a[N][N],n,m,y; 
21 
22 int main(){//freopen("test.in","r",stdin);//freopen("test.out","w",stdout);
23     read(n),read(m);
24     for(register int i=1;i<=n;++i)for(register int j=1;j<=m;++j)read(a[i][j]),dis[i][j]=i+j-2;
25     f[1][1][1][1]=a[1][1];
26     for(register int i=1;i<=n;++i){
27         for(register int j=1;j<=m;++j){
28             for(register int x=i+1;x<=n;++x){
29                 y=dis[i][j]-x+2;
30                 if(y<=0)break;
31                 MAX(f[i][j][x][y],f[i-1][j][x-1][y]);
32                 MAX(f[i][j][x][y],f[i-1][j][x][y-1]);
33                 MAX(f[i][j][x][y],f[i][j-1][x-1][y]);
34                 MAX(f[i][j][x][y],f[i][j-1][x][y-1]);
35                 f[i][j][x][y]+=a[i][j]+a[x][y];
36             }
37         }
38     }
39     printf("%d\n",f[n-1][m][n][m-1]);
40     return 0;
41 }

 

转载于:https://www.cnblogs.com/saigyouji-yuyuko/p/10692155.html

你可能感兴趣的:(CH5103 [NOIP2008]传纸条[线性DP])