題目描述
烏龜棋的棋盤是一行\(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_1\le 0\) ,那麼最後一次可以使用了一張標有 \(1\) 的卡片,此時\(dp[p_1][p_2][p_3][p_4]=dp[p_1][p_2][p_3][p_4]+a[place]\) 。
如果 \(p_2\le 0\) ,那麼 \(dp[p_1][p_2][p_3][p_4] = dp[p_1][p_2 - 1][p_3][p_4] + a[place]\) 。
如果 \(p_3\le 0\) ,那麼 \(dp[p_1][p_2][p_3][p_4] = dp[p_1][p_2][p_3 - 1][p_4] + a[place]\) 。
如果 \(p_4\le 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;
}