题目大意:
alice和bob玩游戏,现在有n张牌,alice首先开始选牌,他可以选择1,2或者3张。之后bob也可以选择1,2或者3张。现在问我们alice和bob在最优的情况下,谁收集的牌的分数最大。
解题思路:
很显然,我们这里需要用DP来转移。每次轮到一位玩家的时候可以选择1,2,3张。令dp[n]表示抽到第n张牌的时候,玩家的最高得分,那么这里,我们得到
上面分别表示我们拿取1,2,3个的情况。f(n)表示第n张牌之后 本次玩家能拿的分数(注意,以第一个式子为例,这里不能够用dp[n+1]因为下一次下手的是另外一个人,dp[n+1]表示的是下一个玩家的最优得分,并不是本次玩家的最优得分,所以不能由dp[n+1]这样来转移)。
所以这里我们需要用到后缀和。f(n) = post[n] - dp[n]. 其中post[n]表示后缀和。把f(n)替换后就得到了正确的转移了。
class Solution {
public:
const int MAXN= 5e4+10;
vector<int> arrmv;
vector<int> post;
vector<int> dp;
int N;
int dfs(int n){
if(n == N)return dp[n]=0;
if(dp[n]!=-1e9)return dp[n];
dp[n] = arrmv[n] + post[n+1]-dfs(n+1);
int no1 = -1e9,no2=-1e9;
if(n+2<=N) no1 = arrmv[n]+arrmv[n+1] + post[n+2] - dfs(n+2);
if(n+3<= N)no2 = arrmv[n]+arrmv[n+1]+arrmv[n+2] + post[n+3] - dfs(n+3);
return dp[n] = max(dp[n],max(no1,no2));
}
string stoneGameIII(vector<int>& mv) {
arrmv.assign(MAXN,0);
dp.assign(MAXN,-1e9);
post= arrmv;
for(int i=0;i<(int)mv.size();i++)arrmv[i+1]=mv[i];
post= arrmv;
N = mv.size()+1;
int n = mv.size();
for(int i=n;i>=1 ;i --)post[i]+=post[i+1];
int alice=dfs(1);
int bob = post[1]-alice;
if(alice > bob)return "Alice";
else if(alice<bob)return "Bob";
else return "Tie";
}
};