题目链接:https://www.luogu.com.cn/problem/P1006
就是从左上到右下,取两条不相交路径,使得总分值最大设f[i][j][k][l]表示第一次走到(i,j),第二次走到(k,l)的最大分值,则有:1)若不在起点或终点,且i=k,j=l,说明两次走到了不在起点或终点的同一个位置,此时f[i][j][k][l]=-inf;2)否则 f[i][j][k][l]=max(f[i-1][j][k-1][l],f[i][j-1][k-1][l],f[i-1][j][k][l-1],f[i][j-1][k][l-1])+a[i][j]+a[k][l],意思就是两次分别都从前一个格子转移而来,每个之前的格子可以向右或向下走,会产生4种转移,最后加上a[i][j]和a[k][l]当前格子的值
我一开始写的转移方程是:1)若不在起点或终点,且i=k,j=l,说明两次走到了不在起点或终点的同一个位置,此时f[i][j][k][l]=-inf;2)f[i][j][k][l]=max(f[i-1][j][k][l]+a[i][j],f[i][j-1][k][l]+a[i][j],f[i][j][k-1][l]+a[k][l],f[i][j][k][l-1]+a[k][l]);但是实际操作了一下发现这个方程会走重复的路径,其实就是把最长的路径走了两遍。然后又改成了上面的方程。现在还在想严格说明为什么上面的方程可以保证路径可以保证路径不相交,但是这个不可以呢?这个我只能感觉一下............留个坑待填吧
正解代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=55; 4 const int inf=0x3f3f3f3f; 5 int a[maxn][maxn],f[maxn][maxn][maxn][maxn]; 6 int m,n,i,j,k,l,t; 7 8 int main(){ 9 freopen("luogu1006.txt","r",stdin); 10 cin>>m>>n; 11 for (i=1;i<=m;i++) 12 for (j=1;j<=n;j++) cin>>a[i][j]; 13 memset(f,0,sizeof(f)); 14 for (i=1;i<=m;i++) 15 for (j=1;j<=n;j++) 16 for (k=1;k<=m;k++) 17 for (l=1;l<=n;l++){ 18 if (i==1&&j==1&&k==1&&l==1) continue; 19 if ((i==k&&j==l)&&(!(i==m&&j==n&&k==m&&l==n))) { //不是终点 ,同一位置 20 f[i][j][k][l]=-inf;continue; 21 } 22 t=max(max(f[i-1][j][k-1][l],f[i-1][j][k][l-1]),max(f[i][j-1][k-1][l],f[i][j-1][k][l-1])); //* 23 f[i][j][k][l]=t+a[i][j]+a[k][l]; 24 } 25 cout<<f[m][n][m][n]<<endl; 26 fclose(stdin); 27 return 0; 28 }
从进阶指南上看到还有一种巧妙一些的状态设计,把维数降到3。设f[i][j][k]表示每次走了i步,第一次走到第j行,第二次到第k行能得到的最大值。由于在第j行走i步,所以第一次走到(j,i+2-j),同理第二次走到(k,i+2-k)。则有转移方程:1)若i≠n+m-2且j=k,则f[i][j][k]=-inf;2)f[i][j][k]=max(f[i-1][j-1][k-1],f[i-1][j][k-1],f[i-1][j-1][k],f[i-1][[j][k])+a[j,i+2-j]+a[k,i+2-k]。和第一个方程一样,这儿max()里的四个值也表示由4种之前的状态转移得到当前状态
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=50+5; 4 const int inf=0x3f3f3f3f; 5 int a[maxn][maxn]; 6 int f[maxn*2][maxn][maxn]; 7 int n,m,i,j,k,t; 8 9 int main(){ 10 //freopen("luogu1006.txt","r",stdin); 11 cin>>n>>m; 12 for (i=1;i<=n;i++) 13 for (j=1;j<=m;j++) cin>>a[i][j]; 14 memset(f,0,sizeof(f)); 15 for (i=1;i<=n+m-2;i++) 16 for (j=1;j<=n;j++) 17 for (k=1;k<=n;k++) 18 if ((i+2>j)&&(i+2>k)){ 19 if (i!=n+m-2&&j==k){ //不是终点,且走到同一位置 20 f[i][j][k]=-inf;continue; 21 } 22 f[i][j][k]=max(max(f[i-1][j-1][k-1],f[i-1][j][k-1]),max(f[i-1][j-1][k],f[i-1][j][k]))+a[j][i+2-j]+a[k][i+2-k]; 23 } 24 cout<<f[n+m-2][n][n]<<endl; 25 //fclose(stdin); 26 return 0; 27 }