经典区间 DP & 经典博弈游戏

简介: 经典区间 DP & 经典博弈游戏

网络异常,图片无法展示
|


题目描述



这是 LeetCode 上的 877. 石子游戏 ,难度为 中等


Tag : 「区间 DP」、「博弈论」


亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子 piles[i] 。


游戏以谁手中的石子最多来决出胜负。石子的总数是奇数,所以没有平局。


亚历克斯和李轮流进行,亚历克斯先开始。 每回合,玩家从行的开始或结束处取走整堆石头。 这种情况一直持续到没有更多的石子堆为止,此时手中石子最多的玩家获胜。


假设亚历克斯和李都发挥出最佳水平,当亚历克斯赢得比赛时返回 true ,当李赢得比赛时返回 false 。


示例:


输入:[5,3,4,5]
输出:true
解释:
亚历克斯先开始,只能拿前 5 颗或后 5 颗石子 。
假设他取了前 5 颗,这一行就变成了 [3,4,5] 。
如果李拿走前 3 颗,那么剩下的是 [4,5],亚历克斯拿走后 5 颗赢得 10 分。
如果李拿走后 5 颗,那么剩下的是 [3,4],亚历克斯拿走后 4 颗赢得 9 分。
这表明,取前 5 颗石子对亚历克斯来说是一个胜利的举动,所以我们返回 true 。
复制代码


提示:


  • 2 <= piles.length <= 500
  • piles.length 是偶数。
  • 1 <= piles[i] <= 500
  • sum(piles) 是奇数。


动态规划



定义 f[l][r]f[l][r] 为考虑区间 [l,r][l,r],在双方都做最好选择的情况下,先手与后手的最大得分差值为多少。


那么 f[1][n]f[1][n] 为考虑所有石子,先手与后手的得分差值:


  • f[1][n] > 0f[1][n]>0,则先手必胜,返回 True
  • f[1][n] < 0f[1][n]<0,则先手必败,返回 False


不失一般性的考虑 f[l][r]f[l][r] 如何转移。根据题意,只能从两端取石子(令 pilespiles 下标从 11 开始),共两种情况:


  • 从左端取石子,价值为 piles[l - 1]piles[l1];取完石子后,原来的后手变为先手,从 [l + 1, r][l+1,r] 区间做最优决策,所得价值为 f[l + 1][r]f[l+1][r]因此本次先手从左端点取石子的话,双方差值为


piles[l - 1] - f[l + 1][r]piles[l1]f[l+1][r]


  • 从右端取石子,价值为 piles[r - 1]piles[r1];取完石子后,原来的后手变为先手,从 [l, r - 1][l,r1] 区间做最优决策,所得价值为 f[l][r - 1]f[l][r1]因此本次先手从右端点取石子的话,双方差值为


piles[r - 1] - f[l][r - 1]piles[r1]f[l][r1]


双方都想赢,都会做最优决策(即使自己与对方分差最大)。因此 f[l][r]f[l][r] 为上述两种情况中的最大值。


根据状态转移方程,我们发现大区间的状态值依赖于小区间的状态值,典型的区间 DP 问题。


按照从小到大「枚举区间长度」和「区间左端点」的常规做法进行求解即可。


代码:


class Solution {
    public boolean stoneGame(int[] ps) {
        int n = ps.length;
        int[][] f = new int[n + 2][n + 2]; 
        for (int len = 1; len <= n; len++) { // 枚举区间长度
            for (int l = 1; l + len - 1 <= n; l++) { // 枚举左端点
                int r = l + len - 1; // 计算右端点
                int a = ps[l - 1] - f[l + 1][r];
                int b = ps[r - 1] - f[l][r - 1];
                f[l][r] = Math.max(a, b);
            }
        }
        return f[1][n] > 0;
    }
}
复制代码


  • 时间复杂度:O(n^2)O(n2)
  • 空间复杂度:O(n^2)O(n2)


博弈论



事实上,这还是一道很经典的博弈论问题,也是最简单的一类博弈论问题。


为了方便,我们称「石子序列」为石子在原排序中的编号,下标从 11 开始。


由于石子的堆数为偶数,且只能从两端取石子。因此先手后手所能选择的石子序列,完全取决于先手每一次决定。


由于石子的堆数为偶数,对于先手而言:每一次的决策局面,都能「自由地」选择奇数还是偶数的序列,从而限制后手下一次「只能」奇数还是偶数石子。


具体的,对于本题,由于石子堆数为偶数,因此先手的最开始局面必然是 [奇数, 偶数][,],即必然是「奇偶性不同的局面」;当先手决策完之后,交到给后手的要么是 [奇数,奇数][,] 或者 [偶数,偶数][,],即必然是「奇偶性相同的局面」;后手决策完后,又恢复「奇偶性不同的局面」交回到先手 ...


不难归纳推理,这个边界是可以应用到每一个回合。


因此先手只需要在进行第一次操作前计算原序列中「奇数总和」和「偶数总和」哪个大,然后每一次决策都「限制」对方只能选择「最优奇偶性序列」的对立面即可。


同时又由于所有石子总和为奇数,堆数为偶数,即没有平局,所以先手必胜。


代码:


class Solution {
    public boolean stoneGame(int[] piles) {
        return true;
    }
}
复制代码


  • 时间复杂度:O(1)O(1)
  • 空间复杂度:O(1)O(1)


最后



这是我们「刷穿 LeetCode」系列文章的第 No.877 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先将所有不带锁的题目刷完。

在这个

系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。


为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:github.com/SharingSour…


在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。

相关文章
|
5月前
|
算法 测试技术 C++
【动态规划】【 数学】C++算法:514自由之路
【动态规划】【 数学】C++算法:514自由之路
|
4月前
|
算法 机器人
【经典LeetCode算法题目专栏分类】【第5期】贪心算法:分发饼干、跳跃游戏、模拟行走机器人
【经典LeetCode算法题目专栏分类】【第5期】贪心算法:分发饼干、跳跃游戏、模拟行走机器人
|
5月前
|
Shell 网络安全
【错题集-编程题】mari和shiny(动态规划-多源状态线性 dp)
【错题集-编程题】mari和shiny(动态规划-多源状态线性 dp)
|
5月前
|
存储
【错题集-编程题】合唱团(动态规划 - 线性 dp)
【错题集-编程题】合唱团(动态规划 - 线性 dp)
|
5月前
|
算法 测试技术 vr&ar
【动态规划】【C++算法】1340. 跳跃游戏 V
【动态规划】【C++算法】1340. 跳跃游戏 V
|
算法 图形学 C++
游戏洗牌算法——常用+详解最优Knuth_Durstenfeld算法
游戏洗牌算法——常用+详解最优Knuth_Durstenfeld算法
252 0
游戏洗牌算法——常用+详解最优Knuth_Durstenfeld算法
|
索引
【day04】力扣(LeetCode)每日一刷[1306. 跳跃游戏 III ][703. 数据流中的第 K 大元素 ][1337. 矩阵中战斗力最弱的 K 行]
了解学习 跳跃游戏 III , 数据流中的第 K 大元素 , 矩阵中战斗力最弱的 K 行。
198 0
【day04】力扣(LeetCode)每日一刷[1306. 跳跃游戏 III ][703. 数据流中的第 K 大元素 ][1337. 矩阵中战斗力最弱的 K 行]
|
人工智能 算法
[leetcode] 798 得分最高的最小轮调 - 思维dp
轮调实际上是这个样子的: 每次讲最前面的元素放到数组最后,然后将所有元素集体向前移动一位 在当前值a [ i ] ≤ i 的时候会获得1 分,问最大的分是多少? 先说明一个事实: 一次轮调之后,对于除了最前面的每个数,他的下标会减小1 ,而对于最前面的那个数,他的下标直接变为最大 大致分为以下三种情况: 本来a [ i ] 就小于下标i ,轮调之后下标减小值不变,所以依旧会获得1 分 本来a [ i ] = = i ,轮调之后,下标减小而值不变,所以值就比下标大1 ,所以说会失去1 分 本来a [ i ] > i,轮调之后,下标更小,值依旧会大于下标,所以依旧不得分
120 0
[leetcode] 798 得分最高的最小轮调 - 思维dp
2029. 石子游戏 IX : 分情况讨论博弈题
2029. 石子游戏 IX : 分情况讨论博弈题
|
机器学习/深度学习
1751. 最多可以参加的会议数目 II :「朴素 DP」&「二分优化 DP」
1751. 最多可以参加的会议数目 II :「朴素 DP」&「二分优化 DP」