题意:
n×n的矩阵a,
−1000<=aij<=1000
求从(1, 1)到(n,n)的两条路线(经过的格子可以重复),路线上的数值和最大,每个元素只能被取一次。
思路:
容易得出一个自然的状态表示是第k条对角线上取(k-i, i)和(k-j, j)的最大值。
用刷表法比较容易管理边界。
k, i, j // 可行状态
for (int si = i;si <= i+1;++i) // si, sj走到下一条对角线上的位置
for (int sj = j;sj <= j+1;++sj) {
if (si > n || sj > n || k+1-si > n || k+1-sj > n) continue;
/*....*/
}
一个优化是
我们可以使i总是<=j,即两条路线不交叉(可以相交)。因为一旦交叉,又可以把它们看成是不交叉的。(通过翻转交叉点后的路径)
int a[Maxn+5][Maxn+5], f[Maxn+5][Maxn+5], g[Maxn+5][Maxn+5], n;
int solve() {
rep(i, 1, n) rep(j, 1, n) f[i][j] = -inf;
f[1][1] = a[1][1];
rep(k, 2, n*2-1) {
rep(i, 1, n) rep(j, 1, n) g[i][j] = -inf;
rep(i, 1, n) rep(j, i, n) {
if (f[i][j] <= -inf) continue;
rep(si, i, i+1) rep(sj, j, j+1) {
if (si > sj || si > n || sj > n || k+1-si > n || k+1-sj > n) continue;
int bonus;
if (si == sj)
bonus = a[k+1-si][si];
else
bonus = a[k+1-si][si] + a[k+1-sj][sj];
g[si][sj] = max (g[si][sj], f[i][j] + bonus);
}
}
rep(i, 1, n) rep(j, 1, n) f[i][j] = g[i][j];
}
return f[n][n];
}