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;
}

image

posted @ 2022-10-13 10:49  YHXo  阅读(39)  评论(0)    收藏  举报