P1006 [NOIP2008 提高组] 传纸条
p1006
这道题其实和1004的方格取数差不多。
先放一下四维DP的代码,与之前不同,l从j + 1开始,这样保证了不会有重复的点,中点(n,m)的值为0,所以最后的答案是f[n][m - 1][n - 1][m]。
#include <bits/stdc++.h>
using namespace std;
int n, m, a[52][52], f[52][52][52][52];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
cin >> a[i][j];
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
for (int k = 1; k <= n; k ++)
for (int l = j + 1; l <= m; l ++)
f[i][j][k][l] = max(max(f[i][j - 1][k - 1][l], f[i - 1][j][k][l - 1]), max(f[i][j - 1][k][l - 1], f[i - 1][j][k - 1][l])) + a[i][j] + a[k][l];
cout << f[n][m - 1][n - 1][m] << '\n';
return 0;
}
优化为三维DP,主要是基于这么一个性质:i+j=k+l=step,因为只能向下或者向右走,那么从起点到终点两条路径的长度肯定是一样的,我们可以在第一维枚举step,再枚举两条路径的横/纵坐标,知道了横/纵坐标,通过step可以得到纵/横坐标,这样只需要枚举三维即可,需要去掉重复的。
注意第一维的空间要开大一倍。
(三维比四维快了不止一点......)
#include <bits/stdc++.h>
using namespace std;
const int N = 52;
int n, m, a[N][N], f[N << 1][N][N];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
cin >> a[i][j];
for (int k = 1; k <= n + m - 1; k ++)
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j ++) {
if (k - i + 1 < 1 || k - j + 1 < 1) continue;//纵坐标不合法
f[k][i][j] = max(max(f[k - 1][i][j], f[k - 1][i - 1][j - 1]), max(f[k - 1][i][j - 1], f[k - 1][i - 1][j])) + a[i][k - i + 1] + a[j][k - j + 1];
if (i == j) f[k][i][j] -= a[i][k - i + 1];
}
cout << f[n + m - 1][n][n] << '\n';
return 0;
}


浙公网安备 33010602011771号