【博弈】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] 表示当前取到第 i i 堆且最多可以取 j j 堆时的最大得分
  • 思考初始化:
    • f [ 0 : ] [ 0 : ] = 0 f[0:][0:] = 0
  • 思考状态转移方程
    • f [ i ] [ j ] = m a x ( f [ i ] [ j ] ,   s [ i : ] d f s ( i + x ,   m a x ( 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()

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/106961895