算法竞赛进阶指南, 270 页, 线性DP
本题要点:
1、状态表示:
每一条路径的第i步和所在的坐标点 (x, y) 的关系 x + y == i + 2;
因此,每条路径的三个未知量(i, x, y) 可以用两个 未知量来(i, x)表示 // y == i + 2 - x
dp[i][x1][x2] 表示两条路径长度i,而且第一条路径末尾在x1行,第二条在x2 行,取得的最大值
2、转态转移:
根据路径的走向,分类讨论:
1)第一条:往右, 第二条:往右
2)第一条:往右, 第二条:往下
3)第一条:往下, 第二条:往右
4)第一条:往下, 第二条:往下
//下面以 右右 为例子:
if(x1 == x2) //走到相同的格子,只叠加一次相应的格子 w[x1][y1 + 1]
{
dp[i + 1][x1][x2] = max(dp[i + 1][x1][x2], dp[i][x1][x2] + w[x1][y1 + 1]);
}else{
dp[i + 1][x1][x2] = max(dp[i + 1][x1][x2], dp[i][x1][x2] + w[x1][y1 + 1] + w[x2][y2 + 1]);
}
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MaxN = 60;
int dp[MaxN * 2][MaxN][MaxN]; //dp[i][x1][x2] 表示两条路径长度i,而且第一条路径末尾在x1行,第二条在x2 行,取得的最大值
int m, n; //n行, m列
int w[MaxN][MaxN];
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= m; ++j)
{
scanf("%d", &w[i][j]);
}
}
memset(dp, 0, sizeof(dp));
//边界
dp[0