双线动态规划问题,双线代表有两个状态在同时进行改变,并且互相会影响。
在本题中正反两个方向的传字条其实是一致的,也就是说从小轩到小渊的路径其实可以转化成从小渊到小轩的路径。这样可以将双线过程的起点保持一致。
然后我们设状态数组为:
其中i,j代表小渊纸条的坐标,k,l表示小轩纸条的坐标。那么他们的下一步过程有四种方式,要么都向下或都想右,又或者一下一右,一右一下。那么就可以得到状态转移方程为:
但在这时候还没有将这道题搞定,因为我们没有满足每个点只能被一个纸条走一次这个条件。对于这个条件我们首先观察在同一时刻也就是说走的步数一致的时候如果j和l相等的话一定意味着两个纸条到达了同一个点。那么我们可以让l = j+1开始,这要就可以保证他们的轨迹永远不可能相交。
#include <bits/stdc++.h> using namespace std; #define int long long const int maxn = 55; int n, m; int a[maxn][maxn]; int dp[maxn][maxn][maxn][maxn]; int max(int i, int j, int k, int l) { int ans = 0; ans = ans>i? ans:i; ans = ans>j? ans:j; ans = ans>k? ans:k; ans = ans>l? ans:l; return ans; } signed main() { memset(dp, -1, sizeof(dp)); cin>>n>>m; for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) { cin>>a[i][j]; } } for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) { for (int k=1;k<=n;k++) { for (int l=j+1;l<=m;l++) { dp[i][j][k][l] = max(dp[i-1][j][k-1][l], dp[i-1][j][k][l-1], dp[i][j-1][k-1][l], dp[i][j-1][k][l-1])+a[i][j]+a[k][l]; } } } } cout<<dp[n][m-1][n-1][m]; return 0; }可以看出i+j==k+l==step。那么可以从step入手将四维的数组缩小成三维。
//将四维缩短成三维:dp[k][i][j]。 #include <bits/stdc++.h> using namespace std; const int maxn = 55; int n, m; int a[maxn][maxn]; int dp[maxn*2][maxn][maxn]; int max(int a, int b, int c, int d) { int ans = 0; ans = ans>a? ans:a; ans = ans>b? ans:b; ans = ans>c? ans:c; ans = ans>d? ans:d; return ans; } int main() { cin>>n>>m; for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) { cin>>a[i][j]; } } for (int k=1;k<n+m;k++) { for (int i=1;i<=n;i++) { for (int j=i+1;j<=n;j++) { if (k-i+1<1 || k-j+1<1) //这里是判断纵坐标的合法性,如果纵坐标不合法那就跳过去 continue; dp[k][i][j] = max(dp[k-1][i][j], dp[k-1][i-1][j], dp[k-1][i][j-1], dp[k-1][i-1][j-1])+a[i][k-i+1]+a[j][k-j+1]; } } } cout<<dp[n+m-1][n-1][n]; return 0; }