双线dp,dp[sum][x1][x2] 表示两个纸条传递到位置(x1,y1)、(x2,y2)所获得的最大好心程度和
其中 sum = x1 + y1 = x2 + y2,sum记录横纵坐标和
这样就优化到了三维
同单线dp有点相似,只是此处两条路径不能相交,我们在状态转移的时候让 x1 != x2
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 50 + 5;
int dp[2 * maxn][maxn][maxn];
int num[maxn][maxn];
int main()
{
int T, n, m;
scanf("%d", &T);
while (T--)
{
memset(dp, 0, sizeof(dp));
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf("%d", &num[i][j]);
for (int sum = 3; sum < n + m; sum++)
{
for (int x1 = 1; x1 <= n; x1++) //第一条路的横坐标
{
for (int x2 = x1 + 1; x2 <= n; x2++) //第两条比第一条的横坐标大 ,不让它们相交
{
if (sum - x1 < 1 || sum - x2 < 1) break; //由x+y=sum知 y=sum-x 此处控制y的范围,下同
if (sum - x1 > m || sum - x2 > m) continue;
//状态转移,有四种状态可以转移到当前状态 ,取最大值并加上当前位置的值
dp[sum][x1][x2] = num[x1][sum - x1] + num[x2][sum - x2]
+ max(max(dp[sum - 1][x1][x2], dp[sum - 1][x1 - 1][x2 - 1]),
max(dp[sum - 1][x1 - 1][x2], dp[sum - 1][x1][x2 - 1]));
}
}
}
int t = n + m; //最终结果一定是一个向下走,一个向右走
dp[t][n][n] = max(dp[t - 1][n][n - 1], dp[t - 1][n - 1][n]);
printf("%d\n", dp[t][n][n]);
}
return 0;
}