计蒜客-2098-乌龟棋-四维dp

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

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

乌龟棋中 MM 张爬行卡片,分成 44 种不同的类型(MM 张卡片中不一定包含所有 44 种类型的卡片见样例),每种类型的卡片上分别标有 11、22、33、44 四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。

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

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

输入格式
第 11 行 22 个正整数 NN 和 MM ,分别表示棋盘格子数和爬行卡片数。

第 22 行 NN 个非负整数,a_1a
1

, a_2a
2

, ……, a_Na
N

,其中 a_ia
i

表示棋盘第 ii 个格子上的分数。

第 33 行 MM 个整数,b_1b
1

, b_2b
2

, ……, b_Mb
M

,表示 MM 张爬行卡片上的数字。

输入数据保证到达终点时刚好用光 MM 张爬行卡片,即 N - 1 = \sum_1^M{b_i}N−1=∑
1
M

b
i

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

数据范围
对于 30%30% 的数据有 1 \le N \le 301≤N≤30, 1 \le M \le 121≤M≤12。

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

对于 100%100% 的数据有 1 \le N \le 3501≤N≤350 ,1 \le M \le 1201≤M≤120 ,且 44 种爬行卡片,每种卡片的张数不会超过 4040;

0 \le a_i \le 1000≤a
i

≤100,1 \le i \le N1≤i≤N ;1 \le b_i \le 41≤b
i

≤4,1 \le i \le M1≤i≤M。输入数据保证 N - 1 = \sum_1^M{b_i}N−1=∑
1
M

b
i

样例说明
样例1:
小明使用爬行卡片顺序为 11,11,33,11,22,得到的分数为 6+10+14+8+18+17=736+10+14+8+18+17=73。注意,

由于起点是 11 ,所以自动获得第 11 格的分数 66。

输出时每行末尾的多余空格,不影响答案正确性

样例输入1复制
9 5
6 10 14 2 8 8 18 5 17
1 3 1 2 1
样例输出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
样例输出2复制
455

本题其实比较难想到dp,我一开始使用dfs,只能过30%数据,后来网上查了一下,用四维dp,很厉害。。。大概我们可以这样理解,可以注意到,如果要到达终点,也就是所有的卡片必须要全部使用。那么也就是枚举所有的卡片组合,然后找出得分最大的那个即可。当然我们可以这样想,最后一步得到的分数肯定是前一步得到的最大分数加上当前的分数,那么就有四中情况,也就是1,2,3,4,四种情况的最大值,所以我们便可以得到递推式了,并且初始值为a[0]

//@author:hairu,wu
//@from:ahut
#include<iostream>
#include<memory.h>
using namespace std;

int n,m;
int a[400];
int b[5]; 
int f[42][42][42][42];

int main(){
	cin >> n>>m;
	for(int i=1;i<=n;i++){
		cin >> a[i];
	}
	
	memset(b,0,sizeof(b));
	for(int i=0;i<m;i++){
		int x;
		cin >> x;
		b[x]++;
	}
	
	
	//f[i][j][k][h]表示使用i张1,j张2,,,所获得的最大分数
	f[0][0][0][0]=a[1];
	for(int i=0;i<=b[1];i++){
		for(int j=0;j<=b[2];j++){
			for(int k=0;k<=b[3];k++){
				for(int h=0;h<=b[4];h++){
					int x=i+2*j+k*3+h*4;//增加的步数
					//因为从1开始,那么下一步position为x+1,所以取x+1位置的数字 
					if(i) f[i][j][k][h]=max(f[i][j][k][h],f[i-1][j][k][h]+a[x+1]);
					if(j) f[i][j][k][h]=max(f[i][j][k][h],f[i][j-1][k][h]+a[x+1]);
					if(k) f[i][j][k][h]=max(f[i][j][k][h],f[i][j][k-1][h]+a[x+1]);
					if(h) f[i][j][k][h]=max(f[i][j][k][h],f[i][j][k][h-1]+a[x+1]);
				}
			}
		}
	} 
	
	cout<<f[b[1]][b[2]][b[3]][b[4]]<<endl;
	return 0;
}


本题其实比较难,还是要多复习呀。。。

发布了83 篇原创文章 · 获赞 3 · 访问量 1378

猜你喜欢

转载自blog.csdn.net/weixin_41296877/article/details/105198415