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]
不想写了