一个地图,走一次之后权值被取走,再走一次,求两次之和最大。
如果只走一次,显然是DP, (二维DP),f[i][j]表示走到(i,j)时最大权值,但是DP一次只能求得最优解,不能记录走了哪些格子。
我们不妨两次路径同时考虑,f[x][y][k][l]表示第一次走到(x,y),第二次走到(k,l)的最优解,状态转移从四种方案中选择(第一次向下/右,第二次向下/右),再加上(x,y)和(k,l)的权值,注意如果这两个点相同,只加一次,因为走了一次已经被取走了,这样就可以保证后面的结果不会出现重复加的情况。
#include <bits/stdc++.h>
using namespace std;
int f[10][10][10][10];
int n, a[10][10];
int main() {
cin >> n;
while (1) {
int x, y, k;
cin >> x >> y >> k;
if (x == 0) break;
a[x][y] = k;
}
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j ++)
for (int k = 1; k <= n; k ++)
for (int l = 1; l <= n; l ++) {
f[i][j][k][l] = max(max(f[i - 1][j][k - 1][l], f[i - 1][j][k][l - 1]), max(f[i][j - 1][k - 1][l], f[i][j - 1][k][l - 1])) + a[i][j] + a[k][l];
if (i == k && j == l) f[i][j][k][l] -= a[i][j];
}
cout << f[n][n][n][n];
}
如果本题数据范围再大点,n^4太高,考虑降维。
两种方案同时进行,走的相同步数k,x+y=k,知道一个坐标通过k可以求出另一个,所以可以降为三维,f[k][y1][y2]是两次都走了k步,分别走到纵坐标y1,y2的最优解。再判断重复。
#include <bits/stdc++.h>
using namespace std;
int n, a[10][10], f[20][10][10];
int main() {
cin >> n;
while (1) {
int x, y, k;
cin >> x >> y >> k;
if (x == 0) break;
a[x][y] = k;
}
for (int k = 1; k <= 2 * n; k ++)
for (int i = 1; i <= min(k, n); i ++)
for (int j = 1; j <= min(k, n); j ++) {
f[k][i][j] = max(max(f[k - 1][i][j], f[k - 1][i - 1][j]), max(f[k - 1][i][j - 1], f[k - 1][i - 1][j - 1])) + a[k - i][i] + a[k - j][j];
if (i == j) f[k][i][j] -= a[k - i][i];
}
cout << f[2 * n][n][n];
}