CH5103 [NOIP2008]传纸条[线性DP]
给定一个 N*M 的矩阵A,每个格子中有一个整数。现在需要找到两条从左上角 (1,1) 到右下角 (N,M) 的路径,路径上的每一步只能向右或向下走。路径经过的格子中的数会被取走。两条路径不能经过同一个格子。求取得的数之和最大是多少。N,M≤50。
由于走两条路径,可以直接把两个人未知设计入状态中。$f[x1][y1][x2][y2]$表示两个人分别所在处时最大价值。枚举两个人位置(或者,枚举第一个人所在位置,和第二个人所在行,其列也就由路径步数相等推出来了),每种状态分别由之前2*2四个方向转移即可。
我code可能有bug。。因为这题觉得简单没花太多时间考虑细节。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #define dbg(x) cerr<<#x<<" = "<<x<<endl 8 #define ddbg(x,y) cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl 9 using namespace std; 10 typedef long long ll; 11 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;} 12 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;} 13 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 14 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 15 template<typename T>inline 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 }