題目背景
小明過生日的時候,爸爸送給他一副烏龜棋當作禮物。
題目描述
烏龜棋的棋盤是一行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_Na
1
,a
2
,…,a
N
,其中a_ia
i
表示棋盤第ii個格子上的分數。
第33行MM個整數,b_1,b_2,…,b_Mb
1
,b
2
,…,b
M
,表示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≤121≤N≤30,1≤M≤12。
對於50\%50%的數據有1≤N≤120,1≤M≤501≤N≤120,1≤M≤50,且44種爬行卡片,每種卡片的張數不會超過2020。
對於100\%100%的數據有1≤N≤350,1≤M≤1201≤N≤350,1≤M≤120,且44種爬行卡片,每種卡片的張數不會超過4040;0≤a_i≤100,1≤i≤N,1≤b_i≤4,1≤i≤M0≤a
i
≤100,1≤i≤N,1≤b
i
≤4,1≤i≤M。
思路
如果我選了卡片i,那麼我就知道了我們在序列中的位置應該在哪。所有卡片一定用完且能到達終點。搞明白這個問題後,我們令dp[i][j][k][l]爲用了i張第一種牌,j張第二種牌,k張第三種牌,l張第四種牌,在序列中的path位置能取得的最大分數,其中path是選取i張第一種牌,j張第二種牌,k張第三種牌,l張第四種牌後的在序列中的位置。首先題目很明確dp[0][0][0][0]=a[1]。每種張牌少一張,就能加一張牌得到當前狀態,能得到如下的方程組:
dp[i][j][k][l]=max(dp[i][j][k][l],dp[i-1][j][k][l]+a[path]) (i≠0)
dp[i][j][k][l]=max(dp[i][j][k][l],dp[i][j-1][k][l]+a[path]) (j≠0)
dp[i][j][k][l]=max(dp[i][j][k][l],dp[i][j][k-1][l]+a[path]) (k≠0)
dp[i][j][k][l]=max(dp[i][j][k][l],dp[i][j][k][l-1]+a[path]) (l≠0)
答案爲dp[card[1]][card[2]][card[3]][card[4]]。
#include <stdio.h>
#include <iostream>
#define N 51
using namespace std;
int dp[N][N][N][N],n,m,s,a[351],card[5];
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
register int i,j,k,l;
cin>>n>>m;
for(i=1;i<=n;i++)
{
cin>>a[i];
}
for(i=1;i<=m;i++)
{
cin>>j;
card[j]++;
}
dp[0][0][0][0]=a[1];
for(i=0;i<=card[1];i++)
{
for(j=0;j<=card[2];j++)
{
for(k=0;k<=card[3];k++)
{
for(l=0;l<=card[4];l++)
{
int path(1+i+j*2+k*3+l*4);//通過枚舉卡牌算出當前位置
if(i!=0) dp[i][j][k][l]=max(dp[i][j][k][l],dp[i-1][j][k][l]+a[path]);
if(j!=0) dp[i][j][k][l]=max(dp[i][j][k][l],dp[i][j-1][k][l]+a[path]);
if(k!=0) dp[i][j][k][l]=max(dp[i][j][k][l],dp[i][j][k-1][l]+a[path]);
if(l!=0) dp[i][j][k][l]=max(dp[i][j][k][l],dp[i][j][k][l-1]+a[path]);
}
}
}
}
cout<<dp[card[1]][card[2]][card[3]][card[4]]<<endl;
return 0;
}