2.乌龟棋
(tortoise.pas/c/cpp)
【问题描述】
小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。
乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数)。棋盘第1格是唯一的起点,第N格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。
……
1 2 3 4 5……N
乌龟棋中M张爬行卡片,分成4种不同的类型(M张卡片中不一定包含所有4种类型的卡片,见样例),每种类型的卡片上分别标有1、2、3、4四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。
游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。
很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。
现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?
【输入】
输入文件名tortoise.in。输入文件的每行中两个数之间用一个空格隔开。
第1行2个正整数N和M,分别表示棋盘格子数和爬行卡片数。
第2行N个非负整数,a1, a2,……, aN,其中ai表示棋盘第i个格子上的分数。
第3行M个整数,b1,b2,……, bM,表示M张爬行卡片上的数字。
输入数据保证到达终点时刚好用光M张爬行卡片,即N−1=ΣMib1。
【输出】
输出文件名tortoise.out。
输出只有1行,1个整数,表示小明最多能得到的分数。
【输入输出样例1】
tortoise.in
9 5
6 10 14 2 8 8 18 5 17
1 3 1 2 1
tortoise.out
73
【输入输出样例1说明】
小明使用爬行卡片顺序为1,1,3,1,2,得到的分数为6+10+14+8+18+17=73。注意,
由于起点是1,所以自动获得第1格的分数6。
【输入输出样例2】
tortoise.in
13 8
4 96 10 64 55 13 94 53 5 24 89 8 30
1 1 1 1 1 2 4 1
tortoise.out
455
【数据范围】
对于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=ΣMib。
这道题是一道DP。。(这不废话。。)
每次出牌要记录的状态很多,每一次出的牌和剩下的牌,位置,分数。。
但题上说最多只有4种卡片,所以我们可以用dfs来实现每一个状态;
dfs中声明4个参数来记录每一种剩的牌,再开个4维数组发f[i][j][k][l]来记录每种牌分别剩i,j,k,l张时的分数进行记忆化,最后逐步更新答案;
代码如下
- #include<cstdio>
- #include<iostream>
- using namespace std;
- const int maxn=45;
- int f[maxn][maxn][maxn][maxn];
- int g[355];//到第i步最大积分为g[i]
- int dfs(int t1,int t2,int t3,int t4){
- if(f[t1][t2][t3][t4]!=0)return f[t1][t2][t3][t4];
- int &ans=f[t1][t2][t3][t4];
- if(t1!=0&&dfs(t1-1,t2,t3,t4)>ans)ans=f[t1-1][t2][t3][t4];
- if(t2!=0&&dfs(t1,t2-1,t3,t4)>ans)ans=f[t1][t2-1][t3][t4];
- if(t3!=0&&dfs(t1,t2,t3-1,t4)>ans)ans=f[t1][t2][t3-1][t4];
- if(t4!=0&&dfs(t1,t2,t3,t4-1)>ans)ans=f[t1][t2][t3][t4-1];
- ans+=g[t1+t2*2+t3*3+t4*4+1];//该点加上走到终点的权值(用完所有的牌)
- return ans;
- }
- int cnt[10];
- int main(){
- freopen("tortoise.in","r",stdin);
- freopen("tortoise.out","w",stdout);
- int n,m;scanf("%d %d",&n,&m);
- for(int i=1;i<=n;++i)scanf("%d",g[i]);
- int tmp;
- for(int i=1;i<=m;++i){
- scanf("%d",&tmp);
- cnt[tmp]++;
- }
- f[0][0][0][0]=g[1];
- printf("%d\n",dfs(cnt[1],cnt[2],cnt[3],cnt[4]));
- return 0;
- }
介绍了一个基于动态规划的游戏策略问题——乌龟棋。玩家需利用不同类型的爬行卡片,通过最优顺序达到最高得分。问题涉及状态转移方程设计及记忆化搜索。
184

被折叠的 条评论
为什么被折叠?



