題目是:
亞歷克斯和李繼續他們的石子游戲。許多堆石子 排成一行,每堆都有正整數顆石子 piles[i]。遊戲以誰手中的石子最多來決出勝負。
亞歷克斯和李輪流進行,亞歷克斯先開始。最初,M = 1。
在每個玩家的回合中,該玩家可以拿走剩下的 前 X 堆的所有石子,其中 1 <= X <= 2M。然後,令 M = max(M, X)。
遊戲一直持續到所有石子都被拿走。
假設亞歷克斯和李都發揮出最佳水平,返回亞歷克斯可以得到的最大數量的石頭。
粗略思路:
(1)求最大值,採用動態規劃可減少重複計算;
(2)亞歷克斯和李均表現爲最佳水平,即採用同一策略進行遊戲,所以動態規劃數組唯一。
詳細思路:
(1)選取結果受M和當前的座標i 影響,所以是動態規劃的數據是二維數組;
(2)剩下的石頭如果小於2M,可以把剩下的所有石頭拿走,可作爲動態規劃的起始條件;
(3)當前可取的石子爲,剩下的所有石頭 - 上一次取走的石頭,求當前可取石頭的最大值,所以遞歸式爲
dp[i][j]=max(dp[i][j],resum[i]-dp[i+x][max(j,x)]);
其中resum[i]爲剩下的所有石頭,上一次取走的石頭dp[i+x][max(j,x)],x爲這次取的石頭堆數,max(j,x)即M = max(M, X)。
代碼如下:
class Solution {
public:
int stoneGameII(vector<int>& piles) {
int n=piles.size();
//設置二維動態規劃數組,分別式當前回合的起始座標和M
vector<vector<int>> dp(n,vector<int>(n,0));
//求剩下的所有石頭總和
vector<int> resum(n,0);
int sum=0;
for(int i=n-1;i>=0;i--)
{
sum+=piles[i];
resum[i]=sum;
}
//初始化動態規劃初始條件,剩下的石頭如果小於2M,可以把剩下的所有石頭拿走
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(i+2*j>=n)
{
dp[i][j]=resum[i];
}
}
}
//遞歸
for(int i=n-1;i>=0;i--)
{
for(int j=n-1;j>=0;j--)
{
for(int x=1;x<=2*j && i+x<n;x++)
dp[i][j]=max(dp[i][j],resum[i]-dp[i+x][max(j,x)]);
}
}
//返回起始座標爲0,M爲1時,亞歷克斯可以得到的最大數量的石頭
return dp[0][1];
}
};