Alice 和 Bob 继续他们的石子游戏。许多堆石子 排成一行 ,每堆都有正整数颗石子 piles[i]。游戏以谁手中的石子最多来决出胜负。
Alice 和 Bob 轮流进行,Alice 先开始。最初,M = 1。
在每个玩家的回合中,该玩家可以拿走剩下的 前 X 堆的所有石子,其中 1 <= X <= 2M。然后,令 M = max(M, X)。
游戏一直持续到所有石子都被拿走。
假设 Alice 和 Bob 都发挥出最佳水平,返回 Alice 可以得到的最大数量的石头。
示例 1:
输入:piles = [2,7,9,4,4]
输出:10
解释:如果一开始 Alice 取了一堆,Bob 取了两堆,然后 Alice 再取两堆。Alice 可以得到 2 + 4 + 4 = 10 堆。
如果 Alice 一开始拿走了两堆,那么 Bob 可以拿走剩下的三堆。在这种情况下,Alice 得到 2 + 7 = 9 堆。返回 10,因为它更大。
示例 2:
输入:piles = [1,2,3,4,5,100]
输出:104
提示:
1 <= piles.length <= 1001 <= piles[i] <= 10^4
分析:
要求出爱丽丝可以得到的最大数量的石头,可以先求出爱丽丝最多比鲍勃多拿的石头数量,再经过计算得到爱丽丝最多可以得到的石头数量。而在两方都采取最优策略的情况下,求其中一方的得分,这种情况可以用记忆化搜索来解题。
令数组 piles 的长度为 n。令 dfs(i,m) 表示前 i 堆石头已经被取走,当前的 M=m 的情况下,接下去取石头的玩家可以比另一方多取的石头数。边界情况为 i=n 时,当前玩家没有石头可以取,状态值为 0。其他情况下,需要遍历当前玩家取 x=1∼2m 堆石头,并减去对方玩家多取的石头数,挑选出最大值来作为最优策略,从而进行状态转移,即
刚开局时,爱丽丝执先手,她比鲍勃多拿的石头数即为 dfs(0,1)。记石头总数为 sum,她最多拿的石头数即为 (dfs(0,1)+sum)/2。
cpp
int min(int a,int b)
{
return a<b?a:b;
}
int max(int a,int b)
{
return a>b?a:b;
}
int stoneGameII(int* piles, int pilesSize) {
int n=pilesSize,dp[n+1][n+1];
for(int i=0;i<=n;++i)
for(int j=0;j<=n;++j)
dp[i][j]=INT_MIN,dp[n][j]=0;
for(int i=n-1;i>=0;--i)
{
for(int m=1;m<=n;++m)
{
int sum=0;
for(int x=1;x<=2*m;++x)
{
if(i+x>n)break;
sum+=piles[i+x-1];
dp[i][m]=max(dp[i][m],sum-dp[i+x][min(n,max(m,x))]);
}
}
}
int sum=0;
for (int i=0;i<n;i++)
sum+=piles[i];
return (dp[0][1]+sum)/2;
}