【博弈】B001_LC_石子游戲 II(記憶化搜索 / 純 dp)

一、Problem

亞歷克斯和李繼續他們的石子游戲。許多堆石子 排成一行,每堆都有正整數顆石子 piles[i]。遊戲以誰手中的石子最多來決出勝負。

亞歷克斯和李輪流進行,亞歷克斯先開始。最初,M = 1。

在每個玩家的回合中,該玩家可以拿走剩下的 前 X 堆的所有石子,其中 1 <= X <= 2M。然後,令 M = max(M, X)。

遊戲一直持續到所有石子都被拿走。

假設亞歷克斯和李都發揮出最佳水平,返回亞歷克斯可以得到的最大數量的石頭。

輸入:piles = [2,7,9,4,4]
輸出:10
解釋:
如果亞歷克斯在開始時拿走一堆石子,李拿走兩堆,接着亞歷克斯也拿走兩堆。在這種情況下,亞歷克斯可以拿到 2 + 4 + 4 = 10 顆石子。 
如果亞歷克斯在開始時拿走兩堆石子,那麼李就可以拿走剩下全部三堆石子。在這種情況下,亞歷克斯可以拿到 2 + 7 = 9 顆石子。
所以我們返回更大的 10。 

提示:

1 <= piles.length <= 100
1 <= piles[i] <= 10 ^ 4

二、Solution

方法一:記憶化

記憶化也可以用 dp 的角度來分析

  • 定義狀態
    • f[i][j]f[i][j] 表示當前取到第 ii 堆且最多可以取 jj 堆時的最大得分
  • 思考初始化:
    • f[0:][0:]=0f[0:][0:] = 0
  • 思考狀態轉移方程
    • f[i][j]=max(f[i][j], s[i:]dfs(i+x, max(x,m))f[i][j] = max(f[i][j],\ s[i:] - dfs(i+x,\ max(x, m))

這裏要注意的是:我們是不知道如何狀態轉移才能讓壓力克斯有最大得分,但我們唯一可以確定的就是壓力克斯可以取的堆數 X,而知道 X 後,李開始取石子的起始位置也就確定了,所以我們只能枚舉所有可取到的堆數 X,然後從中選最優

class Solution {
    int n, s[], f[][];

    int dfs(int i, int m) {
        if (i >= n)
            return 0;
        if (i + 2*m >= n)
            return s[i];
        if (f[i][m] != 0)
            return f[i][m];
        int max = 0;
        for (int x = 1; x <= 2*m; x++) {
            max = Math.max(max, s[i] - dfs(i+x, Math.max(x, m)));
        }
        return f[i][m] = max;
    }
    public int stoneGameII(int[] piles) {
        n = piles.length;
        s = new int[n+1];
        f = new int[n][n+100];
        for (int i = n-1; i >= 0; i--)
            s[i] = s[i+1] + piles[i];
        
        return dfs(0, 1);
    }
}

複雜度分析

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

方法二:dp

代辦…


複雜度分析

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