题目
解法
首先不难想到 \(\mathcal O(n^4)\) 的做法:令 \(dp_{x_1,y_1,x_2,y_2}\) 为两个人 同时 走,某时刻分别到达 \((x_1,y_1),(x_2,y_2)\) 的最大收益。需要特判在同一个点的情况。
不过这个状态实际是冗余的,两人的总步数相等,如果我们知道了其中一人的坐标,就相当于知道了总步数,此时只需要知道另一个人的横/纵坐标就可以得到他的坐标。
现在我们枚举总步数 \(l\),令 \(dp_{i,j}\) 为第一个人的横坐标为 \(i\),另一个人的横坐标为 \(j\) 时最大收益。这样两人的坐标分别是:\((i,l-i),(j,l-j)\)。转移有
\[dp_{i,j}=\max\{dp_{i,j},dp_{i-1,j},dp_{i,j-1},dp_{i-1,j-1}\}
\]
这就变成了 \(\mathcal O(n^3)\) 的。
代码
#include <cstdio>
#include <iostream>
using namespace std;
int dp[150][150], n, w[150][150];
int read() {
int x = 0, f = 1; char s;
while((s = getchar()) < '0' || s > '9') if(s == '-') f = -1;
while(s >= '0' && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
return x * f;
}
int main() {
int a, b, c;
n = read();
while(a = read(), b = read(), c = read(), a) w[a][b] = c;
for(int l = 2; l <= (n << 1); ++ l)
for(int i = l - 1; i >= 1; -- i)
for(int k = l - 1; k >= 1; -- k) {
int j = l - i, u = l - k;
dp[i][k] = w[k][u] + max(dp[i - 1][k - 1], max(dp[i - 1][k], max(dp[i][k], dp[i][k - 1])));
dp[i][k] += (i != k) * w[i][j];
}
printf("%d\n", dp[n][n]);
return 0;
}