题目描述
小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。
乌龟棋的棋盘是一行 NNN 个格子,每个格子上一个分数(非负整数)。棋盘第 111 格是唯一的起点,第 NNN 格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。
乌龟棋中 MMM 张爬行卡片,分成 444 种不同的类型(MMM 张卡片中不一定包含所有 444 种类型的卡片,见样例),每种类型的卡片上分别标有 1,2,3,41,2,3,41,2,3,4 四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。
游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。
很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。
现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?输入数据保证到达终点时刚好用光 MMM 张爬行卡片。
对于 100%100\%100% 的数据有 1≤N≤350,1≤M≤1201≤N≤350,1≤M≤1201≤N≤350,1≤M≤120,且 444 种爬行卡片,每种卡片的张数不会超过 404040;0≤ai≤100,1≤i≤N,1≤bi≤4,1≤i≤M0≤a_i≤100,1≤i≤N,1≤b_i≤4,1≤i≤M0≤ai≤100,1≤i≤N,1≤bi≤4,1≤i≤M。
思路
令 dpi,j,k,ldp_{i,j,k,l}dpi,j,k,l 表示使用 iii 张第 111 种卡片,jjj 张第 222 种卡片,kkk 张第 333 种卡片,lll 张第 444 种卡片的最大得分,题目要求输出的即为 dpl1,l2,l3,l4dp_{l1,l2,l3,l4}dpl1,l2,l3,l4,l1,l2,l3,l4l1,l2,l3,l4l1,l2,l3,l4 分别表示四种卡片数量。
边界条件:dp0,0,0,0=a1dp_{0,0,0,0} = a_1dp0,0,0,0=a1,显而易见乌龟棋子自动获得起点格子( 就是不经过任何操作)的分数。
转移方程:容易发现:dpi,j,k,l=max(dpi−1,j,k,l,dpi,j−1,k,l,dpi,j,k−1,l,dpi,j,k,l−1)+ai+j×2+k×3+l×4+1dp_{i,j,k,l} = \max(dp_{i-1,j,k,l},dp_{i,j-1,k,l},dp_{i,j,k-1,l},dp_{i,j,k,l-1}) + a_{i+j\times2+k\times3+l\times4 + 1}dpi,j,k,l=max(dpi−1,j,k,l,dpi,j−1,k,l,dpi,j,k−1,l,dpi,j,k,l−1)+ai+j×2+k×3+l×4+1,至于 ai+j×2+k×3+l×4+1a_{i+j\times2+k\times3+l\times4 + 1}ai+j×2+k×3+l×4+1 而不是 ai+j×2+k×3+l×4a_{i+j\times2+k\times3+l\times4}ai+j×2+k×3+l×4,是因为我们保存时起始点是 a1a_1a1。
时间复杂度 O(l14)O(l1^4)O(l14) ,空间可采用滚动数组优化成三次方的,但是我懒 。

代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int dp[41][41][41][41];
int n,m;
int a[355];
int l1,l2,l3,l4;
signed main() {
scanf("%lld %lld",&n,&m);
for(int i = 1;i <= n;i++) scanf("%lld",&a[i]);
while(m--) {
int inp;
scanf("%lld",&inp);
if(inp == 1) l1++;
else if(inp == 2) l2++;
else if(inp == 3) l3++;
else l4++;
}
dp[0][0][0][0] = a[1];
for(int i = 0;i <= l1;i++) {
for(int j = 0;j <= l2;j++) {
for(int k = 0;k <= l3;k++) {
for(int l = 0;l <= l4;l++) {
if(i + j + k + l == 0) continue;
if(i != 0) dp[i][j][k][l] = max(dp[i][j][k][l],dp[i - 1][j][k][l]);
if(j != 0) dp[i][j][k][l] = max(dp[i][j][k][l],dp[i][j - 1][k][l]);
if(k != 0) dp[i][j][k][l] = max(dp[i][j][k][l],dp[i][j][k - 1][l]);
if(l != 0) dp[i][j][k][l] = max(dp[i][j][k][l],dp[i][j][k][l - 1]);
dp[i][j][k][l] += a[i + j * 2 + k * 3 + l * 4 + 1];
}
}
}
}
printf("%lld\n",dp[l1][l2][l3][l4]);
return 0;
}

278

被折叠的 条评论
为什么被折叠?



