还没睡醒就写的博客
昨晚看电影去了,今天早上好好弥补一下。
乌龟棋
题目描述 Description
小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。 乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数)。棋盘第1格是唯一 的起点,第N格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。
…… 1 2 3 4 5 ……N 乌龟棋中M张爬行卡片,分成4种不同的类型(M张卡片中不一定包含所有4种类型 的卡片,见样例),每种类型的卡片上分别标有1、2、3、4四个数字之一,表示使用这种卡 片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择 一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。 游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到 该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的 分数总和。 很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡 片使用顺序使得最终游戏得分最多。 现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到 多少分吗?
输入描述 Input Description
输入的每行中两个数之间用一个空格隔开。 第1行2个正整数N和M,分别表示棋盘格子数和爬行卡片数。 第2行N个非负整数,a1a2……aN
,其中ai表示棋盘第i个格子上的分数。 第3行M个整数,b1b2……bM
,表示M张爬行卡片上的数字。 输入数据保证到达终点时刚好用光M张爬行卡片,即N - 1=∑(1->M) bi
输出描述 Output Description
输出一行一个整数
数据范围及提示 Data Size & Hint
【数据范围】
对于30%的数据有1 ≤ N≤ 30,1 ≤M≤ 12。
对于50%的数据有1 ≤ N≤ 120,1 ≤M≤ 50,且4 种爬行卡片,每种卡片的张数不会超
过20。
对于100%的数据有1 ≤ N≤ 350,1 ≤M≤ 120,且4 种爬行卡片,每种卡片的张数不会
超过40;0 ≤ ai ≤ 100,1 ≤ i ≤ N;1 ≤ bi ≤ 4,1 ≤ i ≤M。输入数据保证N−1=ΣM
i b
1
时间限制: 1 s
空间限制: 128000 KB
样例输入 Sample Input | 样例输出 Sample Output |
---|---|
13 8 | 455 |
4 96 10 64 55 13 94 53 5 24 89 8 30 | |
1 1 1 1 1 2 4 1 |
题解
这道题是一个四维DP,而且代码非常的壮观。如下图AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxm=41;
int n,m,l[1001],a,b,c,d,e;
int f[maxm][maxm][maxm][maxm];
int main(){
std::ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>l[i];
for(int i=1;i<=m;i++){
cin>>e;
if(e==1) a++;
else if(e==2) b++;
else if(e==3) c++;
else if(e==4) d++;
}
f[0][0][0][0]=l[1];
for(int i=0;i<=a;i++){
for(int j=0;j<=b;j++){
for(int k=0;k<=c;k++){
for(int s=0;s<=d;s++){
// if(f[i][j][k][s]){
f[i+1][j][k][s]=max(f[i+1][j][k][s],f[i][j][k][s]+l[(i+1)+j*2+k*3+s*4+1]);
f[i][j+1][k][s]=max(f[i][j+1][k][s],f[i][j][k][s]+l[i+(j+1)*2+k*3+s*4+1]);
f[i][j][k+1][s]=max(f[i][j][k+1][s],f[i][j][k][s]+l[i+j*2+(k+1)*3+s*4+1]);
f[i][j][k][s+1]=max(f[i][j][k][s+1],f[i][j][k][s]+l[i+j*2+k*3+(s+1)*4+1]);
// }
}
}
}
}
cout<<f[a][b][c][d]<<endl;
return 0;
}
其实这看起来还是相当暴力的有木有。。。。。。
事实上,大多数人拿到这个题目的时候会想到五维DP,因为很容易可以想到用第一维表示当前行走的距离,二维表示用a 张卡1,三维用b张卡2,四维用c 张卡3,五维用d 张卡4。
五维DP列出的状态转移方程为
f[x][i+1][j][k][s]=max(f[x][i+1][j][k][s],f[x][i][j][k][s]+l[x]);
f[x][i][j+1][k][s]=max(f[x][i][j+1][k][s],f[x][i][j][k][s]+l[x]);
f[x][i][j][k+1][s]=max(f[x][i][j][k+1][s],f[x][i][j][k][s]+l[x]);
f[x][i][j][k][s+1]=max(f[x][i][j][k][s+1],f[x][i][j][k][s]+l[x]);
然而你会发现,这个表示距离的状态是可以用四种卡片的每一种卡片使用的张数来推出的,根本不需要额外表示。而且五维DP是会超时的。你交上去会发现不是TLE就是RE。
因此我们就讲讲四维的状态转移方程。
f[i+1][j][k][s]=max(f[i+1][j][k][s],f[i][j][k][s]+l[(i+1)+j*2+k*3+s*4+1]);
f[i][j+1][k][s]=max(f[i][j+1][k][s],f[i][j][k][s]+l[i+(j+1)*2+k*3+s*4+1]);
f[i][j][k+1][s]=max(f[i][j][k+1][s],f[i][j][k][s]+l[i+j*2+(k+1)*3+s*4+1]);
f[i][j][k][s+1]=max(f[i][j][k][s+1],f[i][j][k][s]+l[i+j*2+k*3+(s+1)*4+1]);
首先f[i][j][k][s] 表示的是:当走一步的卡片(简称卡1)选i 张,卡2选j张,卡3选k张,卡4选s张时走出来的最大价值。那么对于每一次选择,我们都枚举一遍所有的选择情况。(选1时,选2时。。。。。。)
然后做一个选择:
1.选。那你走到这个点的最大价值就是f[i][j][k][s] (上一个状态这样取用纸牌走过的路径的最大价值),加上l[(i+1)+j * 2+k * 3+s * 4+1]) 也就是你当前站的格子的价值,这个在输入的时候就是有的,这两个相加就可能是当前的最大状态。看看是否大于本来的状态:f[i+1][j][k][s]
如果大于他,那就更新。