leetcode 1140. Stone Game II(石头游戏II)

文章描述了一个两人游戏,玩家轮流从多堆石头中拿走一定数量的石头,目标是最大化自己的石头数量。提出了两种方法:深度优先搜索(DFS)和动态规划(DP)来解决此问题。在DFS中,通过预计算和数组优化了计算过程,而在DP中,自底向上地构建解决方案。两种方法都基于最大化玩家的优势并最小化对手的机会。

在这里插入图片描述

涉及game的问题,2个player,
现有几堆石头,每堆石头个数为piles[i],
刚开始M=1,
player1先拿石头,可以拿走前 x 堆(假设从第 i 堆开始拿,可以拿 i ~ i+x-1 堆),1 <= x <= 2M,
拿完之后,重置M=max(x, M),
然后player2开始拿,重复这个过程,直到所有的石头被拿完。
问player1最多可以拿多少个石头。

思路:

game理论就是min, max, 尽量做到自己max, 对手min。
枚举所有可能的情况,找到player1最多的石头。

假设从第 i 堆开始拿,
player1拿x堆,那么player1将会得到piles[i] + … + piles[i+x-1]个石头,
M更新为max(x, M),
那么下一次player2从 i+x 堆开始拿,最多拿 2*max(x,M) 堆。
直到石头被拿完。

要枚举所有的 1 <= x <= 2M,
同时M <= n (n为石头堆数),2M >= n-x时,可以一次性拿走剩下所有石头(x=2M时,可以拿完)。

方法1:DFS

用DFS模拟一次player1, player2交替拿石头的过程,
因为中间涉及到计算和的过程:piles[i] + … + piles[i+x-1],
提前计算积分数组pileSum,那么piles[i] + … + piles[i+x-1] = pileSum[i] - pileSum[i+x] (从右到左求和)

dfs(pileSum, i, m, dp)表示player从第 i 堆开始拿x堆石头(遍历所有x),m为当前的M,
保证调用它的player能石头最大化。
dp[i][m]保存从第i堆开始拿,限制为m的最大可拿石头数,可以避免重复计算。

因为最后求的是player1最多拿多少个石头,所以用player1的视角来调用DFS.
player1先拿,从第0堆开始拿,M=1。
所以调用dfs(pileSum, 0, 1, dp)

现在假设到了第 i 堆,
player1从第i堆开始拿走x堆石头后,会得到piles[i] + … + piles[i+x-1]个石头,
pileSum计算的是从右到左的和,因此piles[i] + … + piles[i+x-1] = pileSum[i]-pileSum[i+x]
M更新为max(x, M)

player1拿完之后,player2从i+x堆开始拿,限制为新的M=max(x, M),
根据game理论,对于player2来说,它自己也要石头最大化,
所以从player2的视角调用DFS, dfs(pileSum, i+x, max(x,M), dp)

player2拿完之后,player1可以拿pileSum[i+x] - player2拿的部分,
这就得到了player1最后拿的石头数。

用player1的视角调用DFS时,DFS函数的内部也有player2视角调用的DFS,
反之player2的视角调用DFS时,内部也有player1调用的DFS,
这就解释了game理论中的min, max, 最大化自己,最小化对手。

class Solution {
   
   
    int n = 0;
    public int stoneGameII(int[] piles) {
   
   
        n = piles.length;
        int[][] dp = new int[n][n
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值