2029. 石子游戏 IX : 分情况讨论博弈题

简介: 2029. 石子游戏 IX : 分情况讨论博弈题

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


题目描述



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


Tag : 「博弈论」


AliceBob 轮流进行自己的回合,Alice 先手。每一回合,玩家需要从 stones 中移除任一石子。


如果玩家移除石子后,导致 所有已移除石子 的价值 总和 可以被 33 整除,那么该玩家就 输掉游戏 。 如果不满足上一条,且移除后没有任何剩余的石子,那么 Bob 将会直接获胜(即便是在 Alice 的回合)。 假设两位玩家均采用 最佳 决策。如果 Alice 获胜,返回 true ;如果 Bob 获胜,返回 false


示例 1:


输入:stones = [2,1]
输出:true
解释:游戏进行如下:
- 回合 1:Alice 可以移除任意一个石子。
- 回合 2:Bob 移除剩下的石子。 
已移除的石子的值总和为 1 + 2 = 3 且可以被 3 整除。因此,Bob 输,Alice 获胜。
复制代码


示例 2:


输入:stones = [2]
输出:false
解释:Alice 会移除唯一一个石子,已移除石子的值总和为 2 。 
由于所有石子都已移除,且值总和无法被 3 整除,Bob 获胜。
复制代码


示例 3:


输入:stones = [5,1,2,4,3]
输出:false
解释:Bob 总会获胜。其中一种可能的游戏进行方式如下:
- 回合 1:Alice 可以移除值为 1 的第 2 个石子。已移除石子值总和为 1 。
- 回合 2:Bob 可以移除值为 3 的第 5 个石子。已移除石子值总和为 = 1 + 3 = 4 。
- 回合 3:Alices 可以移除值为 4 的第 4 个石子。已移除石子值总和为 = 1 + 3 + 4 = 8 。
- 回合 4:Bob 可以移除值为 2 的第 3 个石子。已移除石子值总和为 = 1 + 3 + 4 + 2 = 10.
- 回合 5:Alice 可以移除值为 5 的第 1 个石子。已移除石子值总和为 = 1 + 3 + 4 + 2 + 5 = 15.
Alice 输掉游戏,因为已移除石子值总和(15)可以被 3 整除,Bob 获胜。
复制代码


提示:


  • 1 <= stones.length <= 10^51<=stones.length<=105
  • 1 <= stones[i] <= 10^41<=stones[i]<=104


分情况讨论博弈



为了方便,我们用 A 来代指 Alice,用 B 带代指 Bob


A 只有一种获胜方式,是使得 B 在选石子时凑成 33 的倍数;而 B 除了能够通过让 A 凑成 33 的倍数以外,还能通过让游戏常规结束来获胜。


因此整个游戏过程,我们只需要关心「已被移除的石子总和」和「剩余石子个数/价值情况」即可。


更进一步的,我们只需关心已被移除的石子总和是否为 33 的倍数,以及剩余石子的价值与已移除石子总和相加是否凑成 33 的倍数即可。


所以我们可以按照石子价值除以 33 的余数分成三类,并统计相应数量。


不失一般性考虑,某个回合开始前,已移除的石子总和状态为 xx(共三种,分别为除以 33 余数为 001122,其中当状态为 00,且非首个回合时,说明凑成 33 的倍数,游戏结束),剩余石子价值除以 33 的余数 ss 分别为 001122


首先如果当前 x = 1x=1 时,不能选择 s = 2s=2 的石子,否则会导致凑成总和为 33 的倍数而失败;同理 x = 2x=2 时,不能选择 s = 1s=1 的石子;而选择 s = 0s=0 的数字,不会改变 xx 的状态,可看做换手操作。


同时成对的 s = 0s=0 的等价于没有 s = 0s=0 的石子(双方只需要轮流选完这些 s = 0s=0 的石子,最终会回到先手最开始的局面);而选择与 xx 相同的 ss 会导致 xx 改变(即 x = 1x=1 时,选择 s = 1s=1 的石子,会导致 x = 2x=2;而 x = 2x=2 时,选 s = 2s=2 的石子,会导致 x = 1x=1)。


明确规则后,是分情况讨论的过程:


  • s = 0s=0 的石子数量为偶数:此时等价于没有s = 0s=0的石子,我们只需要关心s = 1s=1s = 2s=2即可:
  • s = 1s=1 的石子数量为 00: 这意味着 A 开始选择的只能是 s = 2s=2,此时交给 B 的局面为「x = 2x=2、剩余石子只有 s = 2s=2」,此时 B 只能选 s = 2s=2 的石子,由于 x = 2x=2 且选择的石子 s = 2s=2,因此交由回 A 的局面为「x = 1x=1,剩余是在只有 s = 2s=2」,因此游戏继续的话 A 必败,同时如果在该过程的任何时刻石子被取完,也是 B 直接获胜,即 A 仍为必败
  • s = 2s=2 的石子数量为 00:分析同理,A 只能选 s = 1s=1,此时交给 B 的局面为「x = 1x=1、剩余石子只有 s = 1s=1」,此时 B 只能选 s = 1s=1 的石子,由于 x = 1x=1 且选择的石子 s = 1s=1,因此交由回 A 的局面为「x = 2x=2,剩余是在只有 s = 1s=1」,因此游戏继续的话 A 必败,同时如果在该过程的任何时刻石子被取完,也是 B 直接获胜,即 A 仍为必败
  • s = 1s=1s = 2s=2 的石子数量均不为 00A 选数量不是最多的一类石子,B 下一回合只能选择相同类型的石子(或是无从选择导致失败),然后游戏继续,最终 B 会先进入「只能凑成 33 的倍数」的局面导致失败,即 A 必胜。
  • s = 0s=0 的石子数量为奇数:此时等价于有一次换手机会,该换手机会必然应用在「对必败局面进行转移」才有意义,因此只有s = 1s=1s = 2s=2的石子数量差大于22A的先手优势不会因为存在换手机会而被转移:
  • 两者数量差不超过 22:此时B可以利用「对方凑成33的倍数必败」规则和「优先使用s = 0s=0石子」权利来进入确保自己为必胜态:
  • 举个 🌰,当 s = 1s=1s = 2s=2 的石子数量相等,虽然有 s = 0s=0 的石子,A 先手,但是 A 的首个回合必然不能选 s = 0s=0,否则马上失败结束,因此 A 只能选 s = 1s=1s = 2s=2,此时 B直接选择 s = 0s=0 的石子,交由给 A 的局面 xx 没有发生改变,A 只能选择与首个回合相同的 ss 游戏才能继续,因此局面会变为「B 先手、s = 1s=1s = 2s=2 的石子数量差为 22」,游戏继续,最终 A 会先遇到「只能凑成 33 的倍数」的局面,即 B 必胜
  • 两者数量差不超过 22:此时无论 A 选择数量较少或较多的 sB 都在第二回合马上使用 s = 0s=0 的石子进行换手,A 只能继续选与第一回合相同类型的的石子,游戏才能进行,最终 A 会先遇到「只能凑成 33 的倍数」或「石子被取完」的局面,即 B 必胜
  • 两者数量差超过 22 :此时即使 A 只要确保第一次选择数量较多的 ss,不管 B 是否使用「优先使用 s = 0s=0」的石子,A 都有足够次数数量多 ss 来抵消换手(或是在 B 放弃使用 s = 0s=0 之后马上使用),最终都是 B 最先遇到「只能凑成 33 的倍数」的局面,即 A 获胜


代码:


class Solution {
    public boolean stoneGameIX(int[] stones) {
        int[] cnts = new int[3];
        for (int i : stones) cnts[i % 3]++;
        return cnts[0] % 2 == 0 ? !(cnts[1] == 0 || cnts[2] == 0) : !(Math.abs(cnts[1] - cnts[2]) <= 2);
    }
}
复制代码


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


最后



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


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


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


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

相关文章
mitt.js:小型事件发布订阅库
mitt.js:小型事件发布订阅库
1766 0
|
10月前
|
安全 Java 测试技术
如何创建一个信任所有证书的`TrustManager`
`TrustManager`是Java中用于管理SSL/TLS信任关系的接口,主要用于验证服务器证书。本文介绍了如何创建一个信任所有证书的`TrustManager`,并通过示例代码展示了具体的实现步骤。虽然这种方法在测试环境中很有用,但在生产环境中使用时存在严重的安全风险。
833 3
|
安全 Windows 编解码
怎么设置服务器禁止被ping
怎么设置服务器禁止被ping 如何禁止服务器被ping--怎么设置:频繁地使用Ping命令会导致网络堵塞、降低传输效率,为了避免恶意的网络攻击,一般都会拒绝用户Ping服务器。为实现这一目的,不仅可以在防火墙中进行设置,也可以在路由器上进行设置,并且还可以利用Windows2000/2003系统自身的功能实现。
6136 0
|
数据采集 数据可视化 数据挖掘
R语言在金融数据分析中的深度应用:探索数据背后的市场智慧
【9月更文挑战第1天】R语言在金融数据分析中展现出了强大的功能和广泛的应用前景。通过丰富的数据处理函数、强大的统计分析功能和优秀的可视化效果,R语言能够帮助金融机构深入挖掘数据价值,洞察市场动态。未来,随着金融数据的不断积累和技术的不断进步,R语言在金融数据分析中的应用将更加广泛和深入。
|
11月前
|
缓存 JavaScript 前端开发
深入理解 Vue 3 的 Composition API 与新特性
本文详细探讨了 Vue 3 中的 Composition API,包括 setup 函数的使用、响应式数据管理(ref、reactive、toRefs 和 toRef)、侦听器(watch 和 watchEffect)以及计算属性(computed)。我们还介绍了自定义 Hooks 的创建与使用,分析了 Vue 2 与 Vue 3 在响应式系统上的重要区别,并概述了组件生命周期钩子、Fragments、Teleport 和 Suspense 等新特性。通过这些内容,读者将能更深入地理解 Vue 3 的设计理念及其在构建现代前端应用中的优势。
365 1
深入理解 Vue 3 的 Composition API 与新特性
|
测试技术 程序员 C#
《黑神话:悟空》:从Unity到UE4 —— 游戏引擎迁移的挑战与机遇
【8月更文第26天】近年来,游戏行业的发展突飞猛进,特别是在图形表现力和技术实现上。《黑神话:悟空》是一款备受期待的动作角色扮演游戏,该游戏在早期开发阶段使用了Unity引擎,但为了追求更高的视觉质量和更强大的技术能力,开发团队决定将其迁移到Unreal Engine 4 (UE4)。本文将探讨这一迁移过程中的技术挑战与机遇。
734 1
|
12月前
|
Python
Python量化炒股的数据信息获取—获取沪深股市每日成交概况信息
Python量化炒股的数据信息获取—获取沪深股市每日成交概况信息
183 5
|
10月前
二进制数从0开始的前几个数
二进制数从0开始的前几个数:
1301 0
|
存储 Shell 程序员
使用 Python 和 Pygame 制作游戏:第一章到第五章
使用 Python 和 Pygame 制作游戏:第一章到第五章
527 0
|
机器学习/深度学习 人工智能 自然语言处理
AITC
【6月更文挑战第29天】
426 2