【博弈】A000_LC_石子游戲 III(記憶化搜索 + dp / 純 dp)

一、Problem

Alice and Bob continue their games with piles of stones. There are several stones arranged in a row, and each stone has an associated value which is an integer given in the array stoneValue.

Alice and Bob take turns, with Alice starting first. On each player’s turn, that player can take 1, 2 or 3 stones from the first remaining stones in the row.

The score of each player is the sum of values of the stones taken. The score of each player is 0 initially.

The objective of the game is to end with the highest score, and the winner is the player with the highest score and there could be a tie. The game continues until all the stones have been taken.

Assume Alice and Bob play optimally.

Return “Alice” if Alice will win, “Bob” if Bob will win or “Tie” if they end the game with the same score.

Input: values = [1,2,3,7]
Output: "Bob"
Explanation: Alice will always lose. Her best move will be to take three piles and the score become 6. 
Now the score of Bob is 7 and Bob wins.

二、Solution

方法一:記憶化搜索 + dp

思路
  • 最優策略就是:每一個都從 1-3 堆石子中選 n1n3n(1 \leqslant n \leqslant 3) 堆,並且取的是最大得分,Alice/Bob 可以贏 Bob/Alice 的分數,但結果是未知的,所以這明顯告訴我們取枚舉 Alice/Bob 在每一種取法的最大得分。一般的枚舉和取最優,就離不開下面幾句代碼了:
    for (int i ...)
       dp[i][turn] = max(...)
    
  • 如果要分別模擬兩個人在取石子,那麼問題會變得很困難,比如「先培養 A」,而讓另一方 B 去削減 A 的手段,這樣將會簡化問題。
  • Alice 想贏那麼 Alice 肯定想拿到最大分數,Bob 想贏那麼 bob 肯定想削減 alice 的得分。
算法
  • 定義狀態
    • dp[x][0]dp[x][0] 表示 Alice 取第 x 堆石子可得最大分數
    • dp[x][1]dp[x][1] 表示 Bob 取第 x 堆石子後,可將 Alice 的得分削減的分數
  • 思考狀態轉移方程
    • dp[x][0] = max(dp[x][0], dfs(i+1, turn ^ 1)) + curi<n&&i<x+3i < n \&\& i < x + 3
    • dp[x][1] = min(dp[x][1], dfs(i+1, turn ^ 1)) - curi<n&&i<x+3i < n \&\& i < x + 3
  • 思考輸出:dp[]
class Solution {
    int n, sv[], dp[][];
    boolean[][] vis;
    int dfs(int x, int turn) {
        if (x >= n)       return 0;
        if (vis[x][turn]) return dp[x][turn];
        vis[x][turn] = true;

        if (turn == 0) {
            int cur = sv[x];
            dp[x][turn] = cur + dfs(x+1, turn ^ 1);
            for (int i = x+1; i < n && i < x+3; i++) {
                cur += sv[i];
                dp[x][turn] = Math.max(dp[x][turn], dfs(i+1, turn ^ 1) + cur);
            }
        } else {
            int cur = sv[x];
            dp[x][turn] = dfs(x+1, turn ^ 1) - cur;
            for (int i = x+1; i < n && i < x+3; i++) {
                cur += sv[i];
                dp[x][turn] = Math.min(dp[x][turn], dfs(i+1, turn ^ 1) - cur);
            }
        }
        return dp[x][turn];
    }

    public String stoneGameIII(int[] stoneValue ) {
        n = stoneValue.length; sv = stoneValue; dp = new int[n][2];
        vis = new boolean[n][2];
        int res = dfs(0, 0);
        if (res > 0) return "Alice";
        if (res < 0) return "Bob";
        return "Tie";
    }
}

效率不高,但勉強過

複雜度分析

  • 時間複雜度:O(n)O(n)
  • 空間複雜度:O(n)O(n)

方法二:dp

代辦把…


複雜度分析

  • 時間複雜度:O()O()
  • 空間複雜度:O()O()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章