以传纸条为例
从一个$n \times m$的网格左上角走到右下角,找到两条无交叉重合的路线,要求两条路线上的值之和最大。
状态定义
f[n + m][n][n]
将四位的状态压缩为三维表示
其中 f[k][i][j]
指的是,从两条路起点同时出发,都走了k
步,一个当前位置在第i
行,(第k - i + 1
列),另一个当前位置在第j
行,(第k - j + 1
列),
由三个值确定了当前的两个位置g[i][k - i + 1]和g[j][k - j + 1]
, 两个位置都可能从左边或上边的方格转移过来,因此共有$2 \times 2 = 4$种可能的转移方案:
for(int k = 2; k <= n + m; ++k)
{
for(int i = 1; i < k; ++i)
{
for(int j = 1; j < k ; ++j)
{
int & v = f[k][i][j]; // 两个人都走了k步,f[k][i][k + 1 - i][j][k + 1 - j]
if(i == j && k != n + m)continue; // 除非到了重点,两条路才能停在同一个格子里
v = max(v, g[i][k - i] + g[j][k - j] + f[k - 1][i][j]);
v = max(v, g[i][k - i] + g[j][k - j] + f[k - 1][i][j - 1]);
v = max(v, g[i][k - i] + g[j][k - j] + f[k - 1][i - 1][j]);
v = max(v, g[i][k - i] + g[j][k - j] + f[k - 1][i - 1][j - 1]);
}
}
}