方格取数P1004


我什么时候才能学会dp啊,对于这道题目我的初始想法时二维dp就是普通的求最大路线dp,当前点求的上个最大子点,记录进la[][];
最后通过深搜la数组,将最大路线清空成零,然后再来一次,可以过72分

自己想到的hack
5
1 1 1 1 1
1 2 0 0 0
0 0 2 0 0
0 0 0 2 0
0 0 0 0 2
如果时这样的一个矩阵,第一条最大路线肯定是往对角线那里走,但是因为(1,2)和(2,1)的大小都是1,记录la如果是(1,2)
清理后的数组是
0 0 1 1 1
1 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
实际上我们想的最大路线是这条
0 1 1 1 1
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
这样就能把所有的点吃光
所以说可以被hack掉

然后dp就是想不出咋办,然后又只能看题解怎么dp,题解思路是将两条路径同时加入dp,也就是二维变四维数组
dp[x1][y1][x2][y2]
表示的子问题状态是第一个,第二个点到达(x1,y1)(x2,y2)最大吃掉的数字总数

然后考虑一下什么时候会冲突呢,表示第一个点和第二个点所走步数相同,所以冲突也只能是
x1 = x2 && y1 = y2

考虑四种状态
第一个点是从左边过来的, 第二个点是从左边
第一个点是从上,第二个点是从左
第一个点是从左,第二个点是从上
第一个点是从上,第二个点是从上
然后状态转移方程很简单想,既然要保证步数相同才有意义,那么转移使用的子问题也要同步数
所以
dp[x1][y1][x2][y2]
= max(dp[x1-1][y1][x2-1][y2],dp[x1-1][y1][x2][y2-1],dp[x1][y1-1][x2-1][y2],dp[x1][y1-1][x2][y2-1]) + gra[x1][y1] + gra[x2][y2];
当然还要判断冲突
if(x1 == x2 && y1 == y2) dp[x1][y1][x2][y2] -= gra[x1][y1];

实际上仔细想想就发觉,只要x1 + y1 != x2 + y2都等于0,
代码如下


#include
#define int long long 

using namespace std;
const int N = 13;
int dp[N][N][N][N];
int gra[N][N];
int n;

signed main() {
	cin >> n;
	int x, y, t;
	while (cin >> x >> y >> t, x || y || t) {
		gra[x][y] = t;
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			for (int p = 1; p <= n; p++) {
				for (int q = 1; q <= n; q++) {
					if (i + j != p + q) continue;
					dp[i][j][p][q] = max(dp[i][j][p][q], dp[i - 1][j][p - 1][q] + gra[i][j] + gra[p][q]);
					dp[i][j][p][q] = max(dp[i][j][p][q], dp[i - 1][j][p][q - 1] + gra[i][j] + gra[p][q]);
					dp[i][j][p][q] = max(dp[i][j][p][q], dp[i][j - 1][p - 1][q] + gra[i][j] + gra[p][q]);
					dp[i][j][p][q] = max(dp[i][j][p][q], dp[i][j - 1][p][q - 1] + gra[i][j] + gra[p][q]);
					if (i == p) dp[i][j][p][q] -= gra[i][j];
				}
			}
		}
	}
	cout << dp[n][n][n][n];
	return 0;
}
posted @ 2025-04-23 21:39  hky2023  阅读(2)  评论(0)    收藏  举报