题目描述
乌龟棋的棋盘是一行(N)个格子,每个格子上一个分数(非负整数)。棋盘第(1)格是唯一的起点,第(N)格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。
乌龟棋中(M)张爬行卡片,分成(4)种不同的类型 ,每种类型的卡片上分别标有 (1,2,3,4) 四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。
游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。
很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。
现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?
题目链接
思路
我们发现,每种卡片的数量很少,并且我们的移动格数只和我们使用的牌有关,所以我们可以考虑将每一种牌的使用数量作为状态来进行(DP) 。我们假设 (dp[p_1][p_2][p_3][p_4])表示标有(1)的卡使用了(p_1)张,……,标有(4) 的卡使用了(p_4) 张所能获得的最大分。
接下来考虑状态如何转移。
记当前位置 (place=1+p_1+2p_2+3p_3+p_4)。我们考虑当前状态下上一次用了哪一种卡片。
如果 (p_1le 0) ,那么最后一次可以使用了一张标有 (1) 的卡片,此时(dp[p_1][p_2][p_3][p_4]=dp[p_1][p_2][p_3][p_4]+a[place]) 。
如果 (p_2le 0) ,那么 (dp[p_1][p_2][p_3][p_4] = dp[p_1][p_2 - 1][p_3][p_4] + a[place]) 。
如果 (p_3le 0) ,那么 (dp[p_1][p_2][p_3][p_4] = dp[p_1][p_2][p_3 - 1][p_4] + a[place]) 。
如果 (p_4le 0) ,那么 (dp[p_1][p_2][p_3][p_4] = dp[p_1][p_2][p_3][p_4 - 1] + a[place]) 。
程序实现中四者取最大值即可。
初始条件为:(dp[0][0][0][0] = a[1]) ,即不使用任何卡片时,在第一格,自动获得了第一格的分数。
假设给出的标有 (1,2,3,4) 的卡片数量分别为 (n_1,n_2,n_3,n_4),那么最终答案就是 (dp[n_1][n_2][n_3][n_4]) 。
而 (n_1,n_2,n_3,n_4) 可以放在一个数组中,因此最终总体复杂度约为 (Theta((frac{m}{4})^4)) 。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=360;
const int M=45;
int k,m;
int a[N],dp[M][M][M][M];
int n[5];
int main() {
cin>>k>>m;
for(int i=1;i<=k;i++) cin>>a[i];
for(int i=1;i<=m;i++) {
int x;
cin>>x;
n[x]++;
}
dp[0][0][0][0]=a[1]; //初始化
for(int p1=0;p1<=n[1];p1++) {
for(int p2=0;p2<=n[2];p2++) {
for(int p3=0;p3<=n[3];p3++) {
for(int p4=0;p4<=n[4];p4++) {
int place=1+p1+2*p2+3*p3+4*p4;
if(p1>0) dp[p1][p2][p3][p4]=max(dp[p1][p2][p3][p4],dp[p1-1][p2][p3][p4]+a[place]);
if(p2>0) dp[p1][p2][p3][p4]=max(dp[p1][p2][p3][p4],dp[p1][p2-1][p3][p4]+a[place]);
if(p3>0) dp[p1][p2][p3][p4]=max(dp[p1][p2][p3][p4],dp[p1][p2][p3-1][p4]+a[place]);
if(p4>0) dp[p1][p2][p3][p4]=max(dp[p1][p2][p3][p4],dp[p1][p2][p3][p4-1]+a[place]);
}
}
}
}
cout<<dp[n[1]][n[2]][n[3]][n[4]]<<endl;
return 0;
}