题目是:
亚历克斯和李继续他们的石子游戏。许多堆石子 排成一行,每堆都有正整数颗石子 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];
}
};