[动态规划]乌龟棋

Posted lz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[动态规划]乌龟棋相关的知识,希望对你有一定的参考价值。

题目描述

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

输入

输入每行中两个数之间用一个空格隔开。
第1行2个正整数N和M,分别表示棋盘格子数和爬行卡片数。
第2行N个非负整数,a1,a2,……,aN,其中ai表示棋盘第i个格子上的分数。
第3行M个整数,b1,b2,……,bM,表示M张爬行卡片上的数字。
输入数据保证到达终点时刚好用光M张爬行卡片,即

输出

输出只有1行,1个整数,表示小明最多能得到的分数。

样例输入

9 5 
6 10 14 2 8 8 18 5 17
1 3 1 2 1

样例输出

73

提示

小明使用爬行卡片顺序为1,1,3,1,2,得到的分数为6+10+14+8+18+17=73。注意,由于起点是1,所以自动获得第1格的分数6。
对于100%的数据有1≤N≤350,1≤M≤120,且4种爬行卡片,每种卡片的张数不会超过40;0≤ai≤100,1≤i≤N;1≤bi≤4,1≤i≤M。

 

思路:想法1:用dp[i]表示到达第i格的最高分数,那么它的值可由max{dp[i-1],dp[i-2],dp[i-3],dp[i-4]}+a[i]得到,问题是在执行这一步时这可能有些种类的牌已经用光了,所以这个状态转移方程时错误的。
想法2:既然这样,我们可以想到再增加几类状态,用dp[i][a][b][c][d]来表示用a张‘1’,b张‘2’,c张‘3’,d张‘4’到达第i格时的最高分数,它的值同样可以由前面已得到的值求出,问题是这样要开350*40*40*40*40的数组,占用内存太大,会MLE。
想法3:我们发现,其实上述的i就等于a*1+b*2+c*3+d*4,所以第一维其实可以省去,直接用dp[a][b][c][d]来表示到达第a*1+b*2+c*3+d*4+1格(首先在第1格)时的最高分数,状态转移方程为max{dp[a-1][b][c][d],dp[a][b-1][c][d],dp[a][b][c-1][d],dp[a][b][c][d-1]}+a[a*1+b*2+c*3+d*4+1]。
 
AC代码:
#include <iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

int a[500];
int dp[45][45][45][45];
int tot[5];

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    for(int i=1;i<=m;i++){
        int tmp;
        scanf("%d",&tmp);
        tot[tmp]++;
    }
    for(int i=0;i<=tot[1];i++){
        for(int j=0;j<=tot[2];j++){
            for(int k=0;k<=tot[3];k++){
                for(int l=0;l<=tot[4];l++){
                    int tmp=0;
                    int val=i*1+j*2+k*3+l*4+1;
                    if(i) tmp=max(tmp,dp[i-1][j][k][l]);
                    if(j) tmp=max(tmp,dp[i][j-1][k][l]);
                    if(k) tmp=max(tmp,dp[i][j][k-1][l]);
                    if(l) tmp=max(tmp,dp[i][j][k][l-1]);
                    dp[i][j][k][l]=tmp+a[val];
                }
            }
        }
    }
    printf("%d\n",dp[tot[1]][tot[2]][tot[3]][tot[4]]);
    return 0;
}

 

以上是关于[动态规划]乌龟棋的主要内容,如果未能解决你的问题,请参考以下文章

P1541 乌龟棋

1541 乌龟棋

#luogu整理 P1541 憨八龟 给爷爬(乌龟棋)

动态规划 目录

codevs1068 乌龟棋==洛谷P1541 乌龟棋

[洛谷P1541] 乌龟棋