P1541 乌龟棋
题目背景
小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。
题目描述
乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数)。棋盘第1格是唯一的起点,第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张爬行卡片。
输出格式:输出只有1行,1个整数,表示小明最多能得到的分数。
输入输出样例
9 5
6 10 14 2 8 8 18 5 17
1 3 1 2 1
73
说明
每个测试点1s
小明使用爬行卡片顺序为1,1,3,1,2,得到的分数为6+10+14+8+18+17=73。注意,由于起点是1,所以自动获得第1格的分数6。
对于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。
Solution:
本题题面提醒的那么清楚:只有$1,2,3,4$四种卡片且用完这$4$种卡片刚好能到达$n$。明摆着多维$DP$。
本题由于保证用完$m$张牌能到达终点$n$,所以不用担心多用牌越界的情况,且只有$4$种长度的移动,于是定义状态$f[i][j][p][q]$表示用了$i$张$1$,$j$张$2$,$p$张$3$,$q$张$4$能的获得价值,初始状态$f[0][0][0][0]=w[1]$(表示不用牌就在起点获得$w[1]$的价值)。
不难想到状态转移方程:$f[i][j][p][q]=max(f[i][j][p][q],f[i-1][j][p][q]+w[s1],f[i][j-1][p][q]+w[s2],f[i][j][p-1][q]+w[s3],f[i][j][p][q-1]+w[s4])$(其中$s1,s2,s3,s4$分别表示$4$种情况下走的步数,注意去掉$-1$后越界的情况)
最后输出目标状态$f[a[1]][a[2]][a[3]][a[4]]$($a[i]$为$i$的数量)就$OK$了。
代码:
#include<bits/stdc++.h> #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define Max(a,b) ((a)>(b)?(a):(b)) using namespace std; const int N=400; int n,m,w[N],x,a[5],f[42][42][42][42]; int main(){ ios::sync_with_stdio(0); cin>>n>>m; For(i,1,n)cin>>w[i]; For(i,1,m)cin>>x,a[x]++; f[0][0][0][0]=w[1]; For(i,0,a[1]) For(j,0,a[2]) For(p,0,a[3]) For(q,0,a[4]){ x=1+i+j*2+p*3+q*4; if(i)f[i][j][p][q]=Max(f[i][j][p][q],f[i-1][j][p][q]+w[x]); if(j)f[i][j][p][q]=Max(f[i][j][p][q],f[i][j-1][p][q]+w[x]); if(p)f[i][j][p][q]=Max(f[i][j][p][q],f[i][j][p-1][q]+w[x]); if(q)f[i][j][p][q]=Max(f[i][j][p][q],f[i][j][p][q-1]+w[x]); } cout<<f[a[1]][a[2]][a[3]][a[4]]; return 0; }