leetcode 5379. 石子游戏 III(后缀和 , DP)

题目大意:

alice和bob玩游戏,现在有n张牌,alice首先开始选牌,他可以选择1,2或者3张。之后bob也可以选择1,2或者3张。现在问我们alice和bob在最优的情况下,谁收集的牌的分数最大。

解题思路:

很显然,我们这里需要用DP来转移。每次轮到一位玩家的时候可以选择1,2,3张。令dp[n]表示抽到第n张牌的时候,玩家的最高得分,那么这里,我们得到

\\dp[n] = a[n]+f(n+1)\\ dp[n] = a[n] + a[n +1] +f(n+2)\\ dp[n] = a[n]+ a[n+1] + a[n+2] + f(n+3)

上面分别表示我们拿取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 arrmv;
    vector post;
    vector 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& 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

 

 

 

 

你可能感兴趣的:(leetcode,后缀和)