2018年6月6号(P1541 乌龟棋)

  今天做提高组题时,无意间看见了这道题就立刻兴致勃勃的去做,结果突然发现自己不会dp了,死磕了一下发现自己根本不会

没办法就只好点开题解,瞬间明白(突然觉得自己好笨):

题目:

题目背景

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

题目描述

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

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

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

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

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

输入输出格式

输入格式:

每行中两个数之间用一个空格隔开。

第 11 行 22 个正整数 N,MN,M ,分别表示棋盘格子数和爬行卡片数。

第 22 行 NN 个非负整数, a_1,a_2,…,a_Na1,a2,,aN ,其中 a_iai 表示棋盘第 ii 个格子上的分数。

第 33 行 MM 个整数, b_1,b_2,…,b_Mb1,b2,,bM ,表示M张爬行卡片上的数字。

输入数据保证到达终点时刚好用光 MM 张爬行卡片。

输出格式:

11 个整数,表示小明最多能得到的分数。

输入输出样例

输入样例#1:  复制
9 5
6 10 14 2 8 8 18 5 17
1 3 1 2 1
输出样例#1:  复制
73

说明

每个测试点 1s1s

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

对于 30\%30% 的数据有 1≤N≤30,1≤M≤121N30,1M12 。

对于 50\%50% 的数据有 1≤N≤120,1≤M≤501N120,1M50 ,且 44 种爬行卡片,每种卡片的张数不会超过 2020 。

对于 100\%100% 的数据有 1≤N≤350,1≤M≤1201N350,1M120 ,且 44 种爬行卡片,每种卡片的张数不会超过 4040 ; 0≤a_i≤100,1≤i≤N,1≤b_i≤4,1≤i≤M0ai100,1iN,1bi4,1iM 。

代码君送上:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 long long dp[41][41][41][41],n,m;//f[i][j][k][l]表示四种不相同的卡片
 4 int a[351],b[5],c;
 5 int main()
 6 {
 7     cin>>n>>m;
 8     for(int i=1;i<=n;i++)cin>>a[i];
 9     dp[0][0][0][0]=a[1];
10     for(int i=1;i<=m;i++)
11     {
12         cin>>c;
13         b[c]++;//桶排序来记入不同卡牌
14     }
15     for(int i=0;i<=b[1];i++)
16     for(int j=0;j<=b[2];j++)
17     for(int k=0;k<=b[3];k++)
18     for(int l=0;l<=b[4];l++)//暴力枚举,每一种卡牌使用数量
19     {
20         int t=a[i+2*j+3*k+4*l+1];//加起来
21         if(i)dp[i][j][k][l]=max(dp[i-1][j][k][l]+t,dp[i][j][k][l]);
22         if(j)dp[i][j][k][l]=max(dp[i][j-1][k][l]+t,dp[i][j][k][l]);
23         if(k)dp[i][j][k][l]=max(dp[i][j][k-1][l]+t,dp[i][j][k][l]);
24         if(l)dp[i][j][k][l]=max(dp[i][j][k][l-1]+t,dp[i][j][k][l]);//动态转移方程
//至于这个(a!=0),显然,你要是调用F[a-1][b][c][d],肯定得保证a-1>=0吧。a显然作为卡1个数不可能<0,故取(a!=0)即可根据多维背包的思想,背包DP几个“价值”(即爬行牌种类)开几维即可
25 } 26 cout<<dp[b[1]][b[2]][b[3]][b[4]]; 27 return 0; 28 }

 根据题解

写出来就是舒服

猜你喜欢

转载自www.cnblogs.com/zssmg/p/9147812.html