乌龟棋

来源:互联网 发布:readfile java 编辑:程序博客网 时间:2024/04/28 17:39

小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。 乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数)。棋盘第1格是唯一 的起点,第N格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。

…… 1 2 3 4 5 ……N 乌龟棋中M张爬行卡片,分成4种不同的类型(M张卡片中不一定包含所有4种类型 的卡片,见样例),每种类型的卡片上分别标有1、2、3、4四个数字之一,表示使用这种卡 片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择 一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。 游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到 该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的 分数总和。 很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡 片使用顺序使得最终游戏得分最多。 现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到 多少分吗?

输入的每行中两个数之间用一个空格隔开。 第1行2个正整数N和M,分别表示棋盘格子数和爬行卡片数。 第2行N个非负整数,a1a2……aN

,其中ai表示棋盘第i个格子上的分数。 第3行M个整数,b1b2……bM

,表示M张爬行卡片上的数字。 输入数据保证到达终点时刚好用光M张爬行卡片,即N - 1=∑(1->M) bi

输出一行一个整数

13 8

4 96 10 64 55 13 94 53 5 24 89 8 30

1 1 1 1 1 2 4 1

455

【数据范围】

对于30%的数据有 N 30M 12

对于50%的数据有 N 120M 50,且种爬行卡片,每种卡片的张数不会超

20

对于100%的数据有 N 350M 120,且种爬行卡片,每种卡片的张数不会

超过40 a 100  N b 4 M。输入数据保证N−1=ΣM

b

1


题目链接:

http://wikioi.com/problem/1068/


解题思路:

1.一开始看到这道题,没思路,后来在大神的指引下,我一步步明白了这个解题思路,我尝试着用自己的话来解释这个思路,以及某些我一开始不明白后来想懂了的细节。

做过一定量的动态规划的人都能明显的感觉到这道题需要用动态规划。


2.一开始我是用二维数组的,结果悲剧了。

因为我忽视了一个条件:

每张卡都必须取。

所以这道题不同于01背包那道题。(01背包那道题可选择放与不放,但这道题必须放,否则走不到终点)。

所以,在大神的指引下,用四维数组来表示,如d[牌“1”的数量 i ][牌“2”的数量 j ][牌“3”的数量 k ][牌“4”的数量 p ] 表示用了 i 张 前进步数为 1 的牌, j 张 前进步数为 2 的牌, k 张前进步数为 3 的牌, p 张前进步数为 4 的牌 获得的最大值。

显然,存在递推关系:

m1 = d[i-1][j][k][p] + a[1 + 1*i + 2*j + 3*k + 4*p ]  (i>=1);

m2 = d[i][j-1][k][p] + a[1 + 1*i + 2*j + 3*k + 4*p ]  (j>=1);

m3 = d[i][j][k-1][p] + a[1 + 1*i + 2*j + 3*k + 4*p ]  (k>=1);

m4 = d[i][j][k][p-1] + a[1 + 1*i + 2*j + 3*k + 4*p ]  (p>=1);


d[i][j][k][p]=max{ m1, m2 , m3, m4 };


拿 m1 来解释一下:

假设用了 i , j ,k ,p 张分别前进一二三四步的牌,那么只要i,j,k,p不为0,则可以肯定在前面的某个阶段用过这张牌。

a[1 + 1*i + 2*j + 3*k + 4*p ] 表示每个格子上的分数。

为什么呢?

因为,要注意到是从起点开始的,所以要加1 , 因为是靠牌子来行走的,所以你用个多少张牌,这些牌代表的步数总和+1 就是当前所在的位置。

ok,讲了这么多,来说说怎么实现代码吧。

事实上,我们应该用一个4重循环加上4重判断,4重判断好理解,因为递推式后面一个括号就是一个判断。

先上核心代码。


注意d[0][0][0][0]=a[1] (假设a[]的下标从1开始),因为起始位置是第一格。

这样能保证每张牌都取到并且都只取一次。

刚接触的人可能会有点疑惑,比如第四重for循环,循环了不止一次啊,怎么能保证牌值为4的牌只用一次呢?

请注意我对d[i][j][k][p]的定义。

事实上,假设第一次循环p=2,那么当第二次循环p=3时,此时为了计算d[i][j][k][p],我们必须计算到d[i][j][k][p-1],这就涉及p=2的情况,而且,那么多重情况只是对所有格子的所有取值情况进行模拟,并计算得到每个格子对应的d[i][j][k][p],注意一点,这里是有四个变量能够决定我们的最大值,也就是说,我们单独考虑p的话,我们已经忽视了i,j,k。我们模拟那么多次,因为我们要模拟i,j,k,p所有的线性组合!。

所以,第一重循环都用到了所有p,但是没用到其他牌,j的第一重循环只用到i,j,以此类推,所以,当d[i1][j1][k1][p]与d[i2][j2][k2][p]的p相同时,我们不能说p被重复使用,因为我们改变了i,j,k的值,是的d[i][j][k][p]的值改变了!也就是说,影响d[i][j][k][p]的值不是p的重用造成的,而是i,j,k的某个线性组合造成的。所以p没有被重复使用!

上代码了:

#include <iostream>using namespace std;int sum[5];int d[50][50][50][50];int check_value[360];int max(int a,int b){return a>b?a:b;}int the_tortoise_chess(){d[0][0][0][0]=check_value[1];for(int i=0;i<=sum[1];i++){for(int j=0;j<=sum[2];j++){for(int k=0;k<=sum[3];k++){for(int p=0;p<=sum[4];p++){if(i>=1)d[i][j][k][p]=max(d[i-1][j][k][p]+check_value[1+1*i+2*j+3*k+4*p],d[i][j][k][p]);if(j>=1)d[i][j][k][p]=max(d[i][j-1][k][p]+check_value[1+1*i+2*j+3*k+4*p],d[i][j][k][p]);if(k>=1)d[i][j][k][p]=max(d[i][j][k-1][p]+check_value[1+1*i+2*j+3*k+4*p],d[i][j][k][p]);if(p>=1)d[i][j][k][p]=max(d[i][j][k][p-1]+check_value[1+1*i+2*j+3*k+4*p],d[i][j][k][p]);}}}}return d[sum[1]][sum[2]][sum[3]][sum[4]];} int main(){int check_number,card_number;int card_value;cin>>check_number>>card_number;for(int i=1;i<=check_number;i++){cin>>check_value[i];}for(int i=1;i<=card_number;i++){cin>>card_value;sum[card_value]++;}cout<<the_tortoise_chess();return 0;}


0 0
原创粉丝点击