题目描述
原题目戳这里
小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。
乌龟棋的棋盘是一行 (N) 个格子,每个格子上一个分数(非负整数)。棋盘第 (1) 格是唯一的起点,第 (N) 格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。
乌龟棋中 (M) 张爬行卡片,分成 (4) 种不同的类型( (M) 张卡片中不一定包含所有 (4) 种类型的卡片,见样例),每种类型的卡片上分别标有 (1, 2, 3, 4) 四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。
游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。
很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。
现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?
输入格式
输入文件的每行中两个数之间用一个空格隔开。
第 (1) 行 (2) 个正整数 (N) 和 (M),分别表示棋盘格子数和爬行卡片数;
第 (2) 行 (N) 个非负整数,(a1, a2, a3…… aN) ,其中 (ai) 表示棋盘第 (i) 个格子上的分数;
第 (3) 行 (M) 个整数,(b1, b2, b3…… bM) ,表示 (M) 张爬行卡片上的数字。
输入数据保证到达终点时刚好用光 (M) 张爬行卡片,即 (N-1=b1+b2+b3…… bm)
输出格式
输出只有 (1) 行,(1) 个整数,表示小明最多能得到的分数。
样例输入 1
9 5
6 10 14 2 8 8 18 5 17
1 3 1 2 1
样例输出 1
73
样例说明
小明使用爬行卡片顺序为 (1),(1),(3),(1),(2) ,得到的分数为 (6+10+14+8+18+17=73) 。
注意,由于起点是 (1),所以自动获得第 (1) 格的分数 。
样例输入 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)
然后定义 (dp[i][j][l][k]) 就是 (a) 卡片用了 (i) 张,(b) 卡片用了 (j) 张,(c) 卡片用了 (l) 张,(d) 卡片用了 (k) 张时,可以得到的最大分数值。
接下来的步骤你会发现和上楼梯很像。
如果最后一张是用的 (a) 卡片到达的最大值, 那么很容易就可以看出
if(i != 0)
dp[i][j][l][k] = max(dp[i][j][l][k], dp[i - 1][j][l][k] + 当前位置_point);
如果是用的 (b) 卡片则有
if(j != 0)
dp[i][j][l][k] = max(dp[i][j][l][k], dp[i][j - 1][l][k] + 当前位置_point);
(c,d) 卡片同理。。
所以我们只需要用四重循环遍历就行了。 是不是很简单
部分代码
for(int i = 0; i <= cost[1]; i++) // cost[x]表示x卡片的张数
for(int j = 0; j <= cost[2]; j++)
for(int l = 0; l <= cost[3]; l++)
for(int k = 0; k <= cost[4]; k++) {
int t = 1 + i + j * 2 + l * 3 + k * 4; // 当前走到了什么位置
if(i != 0) dp[i][j][l][k] = max(dp[i][j][l][k], dp[i - 1][j][l][k] + s[t]);
// s数组储存的棋盘对应的每个位置的分数
if(j != 0) dp[i][j][l][k] = max(dp[i][j][l][k], dp[i][j - 1][l][k] + s[t]);
if(l != 0) dp[i][j][l][k] = max(dp[i][j][l][k], dp[i][j][l - 1][k] + s[t]);
if(k != 0) dp[i][j][l][k] = max(dp[i][j][l][k], dp[i][j][l][k - 1] + s[t]);
} // 分情况更新状态