C++——NOIP动态规划例题——乌龟棋【NOIP2010提高组】

来源:互联网 发布:阿里云 可用区 内网 编辑:程序博客网 时间:2024/05/10 14:15

乌龟棋

题目背景

NOIP2010提高组试题。

题目描述

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

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


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

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

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

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

输入格式

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

     

输出格式

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

样例数据 1

输入

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

输出

73

样例数据 2

输入

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。

    输入数据保证:

            

【样例1说明】

小明使用爬行卡片顺序为 1,1,3,1,2,得到的分数为 6+10+14+8+18+17=73 。注意,由于起点是 1,所以自动获得第 1 格的分数 6。

 

#include<iostream>#include<cstdio>using namespace std;int n,m,k,a;int score[351],card[5];int f[42][42][42][42];int readint(){    int i=0,f=1;    char ch;    for(ch=getchar();(ch<'0'||ch>'9') && ch!='-';ch=getchar());    if(ch=='-')    {        f=-1;         ch=getchar();    }    for(;ch>='0' && ch<='9';ch=getchar())        i=(i<<3)+(i<<1)+ch-'0';    return i*f;}int main(){freopen("1.in","r",stdin);n=readint();m=readint();for(int i=1;i<=n;i++) score[i]=readint();for(int i=1;i<=m;i++){k=readint();card[k]++;}f[0][0][0][0]=score[1];for(int i=0;i<=card[1];i++)for(int j=0;j<=card[2];j++)for(int k=0;k<=card[3];k++)for(int p=0;p<=card[4];p++){a=1+i+2*j+3*k+4*p;if(i) f[i][j][k][p]=max(f[i][j][k][p],f[i-1][j][k][p]+score[a]);if(j) f[i][j][k][p]=max(f[i][j][k][p],f[i][j-1][k][p]+score[a]);if(k) f[i][j][k][p]=max(f[i][j][k][p],f[i][j][k-1][p]+score[a]);if(p) f[i][j][k][p]=max(f[i][j][k][p],f[i][j][k][p-1]+score[a]);}cout<<f[card[1]][card[2]][card[3]][card[4]];return 0;}

解题报告:

DP 题目。
F[i][x1][x2][x3][x4]表示走到第i格时,用了x1个1,x2个2,x3个3和x4个4所得的最大得分。那么:
F[i][x1][x2][x3][x4]=max{f[i-1][x1-1][x2][x3][x4], f[i-2][x1][x2-1][x3][x4],f[i-3][x1][x2][x3-1][x4],f[i-4][x1][x2][x3][x4-1]} +a[i]}.
其中f[0][0][0][0][0]=a[0] (编号为0…N-1).
但是,这样的空间复杂度是O(N*40^4
), 太大。

优化一:
  X4=(i-x1-x2*2-x3*3)/4,  所以x4那一维可以省略掉。这样,复杂度为O(N*403).

优化二:
每个 i 仅仅与前面的 i-4, i-3, i-2, i-1 有关,所以可以使用滚动数组。这样的复杂度是O(5*404).
当然,也可以同时使用两种优化。

上面的参考程序使用优化一。
时间复杂度: O(N*M3)。


0 0