Leetcode 1140. 石子游戏 II (博弈dp,前缀和优化,对等化选手)

f[i][M] 表示从位置i开始,取前X堆石子,其中1<=X<=2 * M 的石子最多个数。

f[i][M] 有如下转移,如果 i + 2 * M > n, 即可以将后面的石子全拿完,那么就全部拿完。

否则,枚举X,当前f[i][M] = max( sum(piels[i:]) - f[i+X][M']) 其中M' = max(i, M);

然后我们再用前缀和预处理优化:

class Solution:
    def stoneGameII(self, piles: List[int]) -> int:
        n = len(piles)
        s = [0] * (n + 1)
        for i in range(1, n + 1):
            s[i] = s[i - 1] + piles[i - 1]
        @lru_cache(None)
        def maxNum(start, M):
            if start + 2*M >= n: return s[n] - s[start]
            res = 0
            for i in range(1, 2 * M + 1):
                res = max(res, s[n] - s[start] - maxNum(start + i, max(i, M)))
            return res
        return maxNum(0, 1)

 

更优雅的写法

    def stoneGameII(self, A: List[int]) -> int:
        N = len(A)
        for i in range(N - 2, -1, -1):
            A[i] += A[i + 1]
        from functools import lru_cache
        @lru_cache(None)
        def dp(i, m):
            if i + 2 * m >= N: return A[i]
            return A[i] - min(dp(i + x, max(m, x)) for x in range(1, 2 * m + 1))
        return dp(0, 1)

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值