乌龟棋 (codevs 1068)题解
【问题描述】
小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。 乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数)。棋盘第1格是唯一 的起点,第N格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。乌龟棋中M张爬行卡片,分成4种不同的类型(M张卡片中不一定包含所有4种类型 的卡片,见样例),每种类型的卡片上分别标有1、2、3、4四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到 该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。 很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡 片使用顺序使得最终游戏得分最多。 现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?
【样例输入】
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%的数据有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。
【解题思路】
本题为NOIP2010提高组第二题,当时本人才小学,自然没参加……刚看到这道题,第一个想到的就是贪心,后面发现这题的分类在递推、DP里面,然后逼着自己往DP想……想着想着然后就想到了……
我想到的是传统方法,设f[i,j,k,l]为用了i张走1步的卡片,j张走2步的卡片,k张走3步的卡片,l张走4步的卡片所得到的值,那么f[i,j,k,l]只会与用了这张卡片之前的值有关,明显具有无后效性,一一枚举每张卡片,加上这一格的值,便是所要求得的值。最终结果为所有卡片全部用完的时候,即f[b[1],b[2],b[3],b[4]]。(b数组存储每种卡片的数量,详见代码)
听老师说可以用三维数组解决,求看到了的神犇们附上思路在评论中,不胜感激!
【动规方程】
f[i,j,k,l]:=max(f[i-1,j,k,l],f[i,j-1,k,l],f[i,j,k-1,l],f[i,j,k,l-1])+a[i+j*2+k*3+l*4+1]注意要加1,因为从第一格开始走的。
【边界条件】
这题是不需要边界的,至于为什么可以自行思考……
【代码实现】
1 uses math; 2 var f:array[-1..40,-1..40,-1..40,-1..40]of longint; 3 a:array[1..350]of longint; 4 b:array[1..4]of longint; 5 i,j,k,l,n,m,x:longint; 6 begin 7 readln(n,m); 8 for i:=1 to n do 9 read(a[i]); 10 for i:=1 to m do 11 begin 12 read(x); 13 inc(b[x]);//存储每种卡片的数量 14 end; 15 for i:=0 to b[1] do 16 for j:=0 to b[2] do 17 for l:=0 to b[3] do 18 for k:=0 to b[4] do 19 f[i,j,l,k]:=max(max(f[i-1,j,l,k],f[i,j-1,l,k]),max(f[i,j,l-1,k],f[i,j,l,k-1]))+a[i+j*2+l*3+k*4+1];//动态规划 20 writeln(f[b[1],b[2],b[3],b[4]]); 21 end.