• CJOJ 1087 【NOIP2010】乌龟棋 / Luogu 1541 乌龟棋(动态规划)


    CJOJ 1087 【NOIP2010】乌龟棋 / Luogu 1541 乌龟棋(动态规划)

    Description

    小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。

    乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数)。棋盘第1格是唯一的起点,第N格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。

    乌龟棋中M张爬行卡片,分成4种不同的类型(M张卡片中不一定包含所有4种类型的卡片,见样例),每种类型的卡片上分别标有1、2、3、4四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。

    游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。

    很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。

    现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?

    Input

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

    Output

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

    Sample Input

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

    Sample Output

    73

    Http

    CJOJ:http://oj.changjun.com.cn/problem/detail/pid/1087
    Luogu:https://www.luogu.org/problem/show?pid=1541

    Source

    动态规划

    解决思路

    我们首先想到的是令F[x][a][b][c][d]表示走到x格时用了a格爬1格,b个爬2格,c个爬3格,d个爬4个的卡片所能有的最大得分。那么我们就能得到一个初始的动态转移方程

    [F[x][a][b][c][d]=max egin{cases} F[x-1][a-1][b][c][d]& ext{a!=0}\F[x-2][a][b-1][c][d]& ext{b!=0} \ F[x-3][a][b][c-1][d]& ext{c!=0} \ F[x-4][a][b][c][d-1]& ext{d!=0}end{cases} +Value[x]]

    但是这样是通不过空间限制的。题中已经给出了用这M张卡片一定能到达n格,所以我们可以省掉x那一维数组,直接用a,b,c,d推出x,所以动态转移方程为

    [F[a][b][c][d]=max egin{cases} F[a-1][b][c][d]& ext{a!=0}\F[a][b-1][c][d]& ext{b!=0} \ F[a][b][c-1][d]& ext{c!=0} \ F[a][b][c][d-1]& ext{d!=0}end{cases} +Value[a+b*2+c*3+d*4+1]]

    注意最后要+1,因为起始格是第一格。

    为了简便,我们还是使用记忆化的方法。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int maxN=351;
    const int maxC=41;
    const int inf=2147483647;
    
    int n,m;
    int Card[10]={0};
    int Value[maxN];
    int F[maxC][maxC][maxC][maxC];
    
    int dfs(int a,int b,int c,int d);
    
    int main()
    {
    	int x;
    	cin>>n>>m;
    	for (int i=1;i<=n;i++)
    		cin>>Value[i];
    	for (int i=1;i<=m;i++)
    	{
    		cin>>x;
    		Card[x]++;//直接累加到同类卡片的计数器中
    	}
    	memset(F,-1,sizeof(F));
    	F[0][0][0][0]=Value[1];
    
    	F[Card[1]][Card[2]][Card[3]][Card[4]]=dfs(Card[1],Card[2],Card[3],Card[4]);
    	cout<<F[Card[1]][Card[2]][Card[3]][Card[4]]<<endl;
    	return 0;
    }
    
    int dfs(int a,int b,int c,int d)//记忆化搜索
    {
    	if (F[a][b][c][d]!=-1)
    		return F[a][b][c][d];
    	int k=a+b*2+c*3+d*4+1;
        if (a!=0)
    		F[a][b][c][d]=max(F[a][b][c][d],dfs(a-1,b,c,d));
    	if (b!=0)
    		F[a][b][c][d]=max(F[a][b][c][d],dfs(a,b-1,c,d));
    	if (c!=0)
    		F[a][b][c][d]=max(F[a][b][c][d],dfs(a,b,c-1,d));
    	if (d!=0)
    		F[a][b][c][d]=max(F[a][b][c][d],dfs(a,b,c,d-1));
        F[a][b][c][d]+=Value[k];
    	return F[a][b][c][d];
    }
    
    自己选择的路,跪着也要走完。朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。
  • 相关阅读:
    Thread.currentThread().getName() ,对象实例.getName() 和 this.getName()区别
    CentOS7.7 yum安装新版git
    CentOS使用epel安装不同版本php-fpm
    ubuntu16.04安装mysql5.6
    阿里云Confluence无法发送邮件修复
    windowserver 2012安装openssh
    linux增加history时间戳
    SQL Server 2008R2各个版本,如何查看是否激活,剩余可用日期?
    nginx增加访问验证
    mysql5.6和5.7的权限密码设置
  • 原文地址:https://www.cnblogs.com/SYCstudio/p/7138161.html
Copyright © 2020-2023  润新知