P2010 乌龟棋

这道题目意思大致是这样,但是有点没有说清楚,就是选择完所有的卡牌后才能从起点走到终点

其实这道题目爆搜加上记忆化,也可以过,也就是记忆化可以转化为动态规划,动态规划不一定能转化为记忆化
自己想一想就知道怎么写了
确定子问题和定义状态
dp[i][p][q][j][k],表示以第i个点结尾的还剩下1牌p张,2牌q张,3牌j张,4牌k张,空间复杂度为350 * (40 ^ 4)mel了
(先不管那一些,先把状态转移方程定下)

其实想一想就容易得出状态转移
dp[i][p][q][j][k]=max(dp[i-1][p+1][q][j][k],dp[i-2][p][q+1][j][k],dp[i-3][p][q][j+1][k],dp[i-4][p][q][j][k+1])+gra[i];
这里只是简单写,当然还要考虑i - 牌大小越界问题

转移方程定义下来了,但是数据量超内存了,观察,每一个当前的dp[i][p][q][j][k]只用到了dp[i-1],dp[i-2],dp[i-3],dp[i-4],可以考虑用滚动数组


#include
#define int long long 

using namespace std;
const int N = 3e2 + 55, M = 44;
int dp[5][M][M][M][M];
int cnt[5] = { 0 };
int n, m, gra[N];

signed main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++) cin >> gra[i];
	for (int i = 1; i <= m; i++) {
		int t;
		cin >> t;
		cnt[t]++;
	}
	//for (int i = 1; i <= 4; i++) cout << cnt[i] << ' ';
	dp[1][cnt[1]][cnt[2]][cnt[3]][cnt[4]] = gra[1];
	//发现i只需要使用之前4个,所以滚动数组5个
	for (int i = 2; i <= n; i++) {
		for (int p = 0; p <= cnt[1]; p++) {
			for (int q = 0; q <= cnt[2]; q++) {
				for (int j = 0; j <= cnt[3]; j++) {
					for (int k = 0; k <= cnt[4]; k++) {
						int t = 0;
						if (p < cnt[1] && i - 1 >= 1) {
							dp[i % 5][p][q][j][k] = dp[(i + 4) % 5][p + 1][q][j][k] + gra[i];
							t++;
						}
						if (q < cnt[2] && i - 2 >= 1) {
							if (!t) dp[i % 5][p][q][j][k] = dp[(i + 3) % 5][p][q + 1][j][k] + gra[i];
							else dp[i % 5][p][q][j][k] = max(dp[i % 5][p][q][j][k], dp[(i + 3) % 5][p][q + 1][j][k] + gra[i]);
							t++;
						}
						if (j < cnt[3] && i - 3 >= 1) {
							if(!t) dp[i % 5][p][q][j][k] = dp[(i + 2) % 5][p][q][j + 1][k] + gra[i];
							else dp[i % 5][p][q][j][k] = max(dp[i % 5][p][q][j][k], dp[(i + 2) % 5][p][q][j + 1][k] + gra[i]);
							t++;
						}
						if (k < cnt[4] && i - 4 >= 1) {
							if(!t) dp[i % 5][p][q][j][k] = dp[(i + 1) % 5][p][q][j][k + 1] + gra[i];
							else dp[i % 5][p][q][j][k] = max(dp[i % 5][p][q][j][k], dp[(i + 1) % 5][p][q][j][k + 1] + gra[i]);
							t++;
						}
						if (!t) dp[i % 5][p][q][j][k] = 0;
					}
				}
			}
		}
	}
	//cout << dp[2][1][0][0][0] << endl;
	cout << dp[n % 5][0][0][0][0];
	return 0;
}

虽然最后还是有一个数据tle了,不过也差不多了
实际上要修改的话可以优化一维,就是dp[i][p][q][j][k]中的i那一维
因为i的位置可以通过i = 1 + (cnt[1]-p)1 + (cnt[2]-q)2 + (cnt[3]-j)3 + (cnt[4]-k)4;
这样其实就是存在很多不必要的子问题的判断消耗时间,实际上可以直接变成dp[p][q][j][k]
不想写了

posted @ 2025-04-24 20:52  hky2023  阅读(11)  评论(0)    收藏  举报