在我小时候以前做题的时候,遇到博弈题往往都是漫无目的地打表找规律,或者找一些特殊情况但是没有很好的分析方法。
其实博弈题是有比较套路的解题方法的,那就是利用SG函数,第一节不会讲到SG函数的具体用法,我们先来博弈入个门,学习一下最基本的博弈类型:Nim游戏。
作者:Eriktse
简介:19岁,211计算机在读,现役ACM银牌选手力争以通俗易懂的方式讲解算法!❤️欢迎关注我,一起交流C++/Python算法。(优质好文持续更新中……)
阅读原文获得更好阅读体验:https://www.eriktse.com/algorithm/1110.html
巴什博奕
在进入Nim游戏之前,我们先看一个简单的博弈:巴什博奕。
看这道例题:http://acm.hdu.edu.cn/showproblem.php?pid=1846
由于HDUOJ经常打不开,我这里复制一下题意:
1、 本游戏是一个二人游戏;
2、 有一堆石子一共有n个;
3、 两人轮流进行;
4、 每走一步可以取走1…m个石子;
5、 最先取光石子的一方为胜;
如果游戏的双方使用的都是最优策略,请输出哪个人能赢。
假设此时的n = 10, m = 3
,我们来分析一下这个局面。
我们设一个布尔函数f(x)
,表示当n = x
时的输赢。
- f(0) = 0,因为无法继续操作了,显然是0,也就是说这是一个必败态。
- f(1) = 1,可以取走一个石子,使对手陷入必败态,所以这是一个必胜态。
- f(2) = 1,可以取走两个。
- f(3) = 1,可以取走三个。
- f(4) = 0,无论取走一个、两个或三个都必然使得对手进入必胜态,所以这是一个必败态。
- f(5) = 1
- f(6) = 1
- f(7) = 1
- f(8) = 0,无论取走一个、两个或三个都必然使得对手进入必胜态,所以这是一个必败态。
- f(9) = 1
- f(10) = 1
至此,我们得到了答案,f(n) = f(10) = 1
所以先手必胜,不难发现上面这个函数f(x)
的规律,仅当x % 4 == 0
时为0
,其余情况都为1
。
于是我们只需要判断n % (m + 1)
是否为0
就能判断先手是否获胜。
这就是巴什博奕模型,是不是很简单,我们简单打个表就找到了规律。
Nim游戏
依然看这道例题:https://www.luogu.com.cn/problem/P2197
我们这么分析:
败局一定是全为0的情况,此时所有数字的异或和为0(不知道怎么写异或和的latex,大家凑合着看):
$$\oplus_{i=1}^{n}a_i = 0$$
那么想一下那些状态可以到这个败局呢?我们反向的思考,往任意一个位置加上一个数字,就可以作为前一个状态,也就是一个必胜态(因为那个状态必然可以到达败局的状态)。
往任意一个位置加上一个数字之后就必然有:
$$\oplus_{i=1}^{n}a_i \ne 0$$
再想一下,从一个异或和不为0的状态,是否一定有办法转移到一个异或和为0的状态。
不难发现是一定可以的。
举个栗子:
我们有4
堆石子,数量分别为:1 7 2 6
。这是我随便写的一个数据。
它们的异或和为:1 ^ 7 ^ 2 ^ 6 = (0 1 0)
,那么我可以通过调整2 -> 0
使得异或和为0,现在有1 ^ 7 ^ 0 ^ 6 = 0
,当然我还可以通过6 -> 4
,异或和结果也是0。
不难发现,只需要从数组中找一个最高非零位大于等于异或的结果的最高非零位的数字,然后减少一部分就可以,这样的数是一定存在的。
那么也就是说任意一个异或和非零的状态都可以通过一步转移到异或和为0的状态,任意一个异或和为0的状态不管怎么走一步,都必然转移到异或和非0的状态。
而石子的个数是一直减小的,最终一定会走到全0,异或和为0的状态且一定是败局。
也就是说:
必胜态W(win):异或和非0;
必败态L(lose):异或和为0;
以上就是Nim游戏模型,当然你也可以叫他Nim博弈。
这一节先了解这些,下一节将会讲解SG函数的转移和子游戏的合并。
本文由eriktse原创,创作不易,如果对您有帮助,欢迎小伙伴们点赞、收藏⭐、留言