1140. Stone Game II (DP, DFS)

这篇博客探讨了一种两玩家游戏的策略,其中玩家轮流从数堆中取石子。文章详细介绍了如何使用深度优先搜索(DFS)和动态规划(DP)方法来找到最优策略。DFS解决方案直观且更像是一种实现,而DP方法需要逆向思维。在DP中,我们定义了状态转移方程,以求出从特定位置开始,玩家可以获取的最大石头数量。最终,博客提供了两种算法的实现,并强调了它们的时间复杂度和优化技巧。
摘要由CSDN通过智能技术生成

The DFS solution is quite intuitive and more like an implementation.

Try to think in this way, every time you can either choose X piles, and this X would affect the latter decisions. And as both Alice and Bobs would make decisions optimally. We need to relate these two variables. The difference between the stones of Alice and Bob gotten is the best way to relate them. That's because if we maximize the difference between Alice and Bob, it is the same to help them maximize the stones.

However, the answer required to return Alice's stones. Let's say Alice's stones are a and Bob's stones are b, the difference is a - b and the total stone of the piles is a + b, total - difference = 2a, thus if we want to get the number of Alice's stones. Just need to use the sum of piles of stone to deduct the difference and then divide it by 2. 

What are the base cases? 

If 2 * m is larger than the rest length of the piles, the optimal choice is to take all of them.

For pruning, we would use a memorization array to store the value of different choices, if there are repeating cases, just return the answer. 

class Solution {
public:
    int dfs(vector<int>& piles, int len, int m, vector<vector<int>> &dp){
        if(len >= piles.size())return 0;
        m = min(int(piles.size()), m);
        if(dp[len][m] > 0)return dp[len][m];
        if(piles.size() <= len + m * 2)return dp[len][m] = accumulate(piles.begin() + len, piles.end(), 0);
        int count = 0;
        int best = INT_MIN;
        for(int i = 1; i <= 2 * m; i++){
            count += piles[len + i - 1];
            int n = dfs(piles, len + i, max(i, m), dp);
            best = max(best, count - n);
        }
        return dp[len][m] = best;
        
    }
        
    int stoneGameII(vector<int>& piles) {
        vector<vector<int>> dp(102, vector<int>(102));
        int part = dfs(piles, 0, 1, dp);
        return (accumulate(piles.begin(), piles.end(), 0) + part)/2;

    }
};

For the Dp solution, it is quite hard to think of. We need to think backwardly. In DFS, we try to use recursion to get the base case answer and then accumulate it backwardly. 

As DP is iterative, we need to do our DP reversely.  

Dp[i][j] is the maximum stone that a player can get starting with index i and with j's taken. 

So the equation of the DP would be to total stones deduct opponents value. dp[i][j] = max(total stone form piles i to n  - dp[i + x][x]))

so it would be an O(n^2 M) solution. 

O(n) for iterating the piles from the back to front,

        O(n) for setting different M,

                O(M) for search for the best M. 

class Solution {
public:
        
    int stoneGameII(vector<int>& piles) {
        vector<vector<int>> dp(102, vector<int>(102));
        int n = piles.size();
        int suffix[102] = {0};
        for(int i = n - 1; i >= 0; i--){
            suffix[i] = suffix[i + 1] + piles[i];
        }
        for (int i = 0; i <= n; i++) {
            dp[i][n] = suffix[i];
        }
        for(int i = n - 1; i >= 0; i--){
            for(int j = 1; j <= n - 1; j++){
                for(int x = 1; x <= 2 * j && i + x <= n; x++){
                    dp[i][j] = max(dp[i][j], suffix[i] - dp[i + x][max(j, x)]);
                }
            }
        }
        return dp[0][1];

    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值