【基础操作】博弈论 / SG 函数详解

时间:2024-06-08 16:37:32

  博弈死我了……(话说哪个小学生会玩博弈论提到的这类弱智游戏,还取石子)

  先推荐两个文章链接:浅谈算法——博弈论(从零开始的博弈论) 博弈论相关知识及其应用

  This article was updated at 2019.8.14.

SG函数

  在学习博弈论之前,你需要彻底了解 SG 函数。

  对于一个两人轮流操作的游戏,我们把游戏的每一种可能的局面设为一种局面

  那么局面只分两种:(对于这一轮操作者的)必胜态必败态。至于为什么没有不确定态,看完下文你就明白了。

  若这一轮操作者从这个局面出发,按最优策略能必胜,则称这个局面为必胜态;若按最优策略也是必败,则称这个局面为必败态。

  定义两种局面之间的转换:

    1. 终止局面为必败态

    2. 对于任意的必胜态,存在至少一条路径可以转移到必败态

    3. 对于任意的必败态,只能转移到必胜态

  解释:

    对于第 1 条,这就看游戏定义了。一般都是定义不能合法操作的人输,即到达了游戏的终止局面。

    对于第 2 条,一个玩家虽然在这一轮处于必胜态,但如果他做不当操作,可能会使对手进入必胜态,所以必胜态可能存在转移到必胜态的路径。但这个人会用最优策略,所以他会使对手必败,即选择转移到必败态的路径。所以,这个玩家处于必胜态,当且仅当该局面存在至少一条转移到必败态的路径。

    对于第 3 条,一个玩家无论怎么走都会让对面赢,说明他必败了。也可以根据定义反证 必败态不可能转移到必败态。(定义:若一个玩家通过某个转移使对手进入必败态,那他当前处于必胜态)。

    概括:若一个局面的所有后继都是必胜态,则这个局面为必败态。否则至少有一个后继是必败态,这个局面为必胜态。由于终止局面是必败态,所以从终止局面可以倒推出所有局面要么是必胜态,要么是必败态。这就是为什么博弈游戏不存在不确定态(即判断不出按最优策略是赢还是输)。

  好了,理解了两种局面之间的转换,可以引入 SG(Sprague-Grundy) 函数了。它的定义如下:$$f(v) = \text{mex}\{f(u)\space |\space u∈child[v]\}$$

  其中 $\text{mex(minimal exvludant)}$ 是定义在整数集合上的操作。它的自变量是任意整数集合,函数值是不属于该集合的最小自然数。$$\text{mex}(A) = \min\{k\space |\space \complement_N k\}$$

  那么,终止局面的 SG 值显然为 $0$,并且 SG 值为 $0$ 的局面就是必败态,SG 值不为 $0$ 的局面就是必胜态。

  理解:SG 值为 $0$ 的局面,它的所有后继局面的 SG 值都不为 $0$;SG 值不为 $0$ 的局面,它存在 SG 值为 $0$ 的后继局面。这恰好满足上文所述的两种局面之间的转移。

  所以从终止局面出发,递推出游戏中所有局面的 SG 值即可得知每种局面是必胜还是必败了。

  SG 函数不局限于上述一种定义,只要一个函数满足值为 $0$ 的局面,它的所有后继局面的 SG 值都不为 $0$;值不为 $0$ 的局面,它存在 SG 值为 $0$ 的后继局面,它就可以作为 SG 函数,表示局面是必胜还是必败。

例题 0

  有 $n$ 个石子,$\text{A,B}$ 轮流取 $k$ 个石子,其中 $k∈S$,$S$ 是一个给定的正整数集合。问 $\text{A}$ 先手是否有必胜策略。

sol

  一种石子数量对应一种局面,递推出所有局面的 SG 值即可。

例题 1

  有 $n$ 个式子,$\text{A,B}$ 两人轮流取石子,规定他们每次至多只能取当前石子总数 $\lceil \frac{s}{2} \rceil$ 个式子。问 $\text{A}$ 先手是否有必胜策略。

sol

  列出 $n$ 很小时 $\text{SG}(n)$ 的值,发现 SG 值有规律

  0, 1

  0, 2, 1, 3

  0, 4, 2, 5, 1, 6, 3, 7

  0, 8, 4, 9, 2, 10 ……

  这就是本题的规律,先手必败当且仅当 SG 值为 $0$。

例题 2(Nim 游戏)

  有 $n$ 堆石子,每堆数目分别为 $x_1,x_2,...,x_n$,$\text{A,B}$ 两人每次可以选一堆石子取走任意多个,问 $\text{A}$ 先手是否有必胜策略。

sol

  例题 0 的扩展版本。

  由于这里有多堆石子,我们考虑对每堆石子求出 $\text{SG}(x_i)$。然而由于这里不限制取石子的数量,所以实际上 $\text{SG}(n) = \text{mex}\{\text{SG}(0), \text{SG}(1), ..., \text{SG}(n-1)\}$,归纳可得 $\text{SG}(n) = n$,所以 $\text{SG}(x_i) = x_i$。

  能否由这一些 SG 值得到整局游戏的 SG 值呢?

  Nim 游戏的神奇之处在于它的 SG 值和异或扯上了关系。Nim 游戏中先手必败当且仅当 $x_1\bigoplus x_2\bigoplus ...\bigoplus x_n = 0$($\bigoplus$ 为异或)。

  证明:

    当 Nim 游戏的 SG 值为 $0$ 时,我们假定取第 $k$ 堆中的某些石子,使得 $x_k$ 减成 $x'_k$,我们假设 $x_1\bigoplus x_2\bigoplus ...\bigoplus x_n = 0 = x_1\bigoplus x_2\bigoplus ...\bigoplus x'_k\bigoplus ...\bigoplus x_n$,可得 $x_k=x'_k$,不符合条件,因此在取一轮石子后 SG 值必然发生了改变。

    而对于一个 SG 值不为 $0$ 的局面,我们必然可以通过一个操作,使得 SG 值变为 $0$。设 SG 值为 $sum$,若其最高位为(从个位数起)第 $k$ 位,则至少存在一个 $x_i$,其第 $k$ 位是 $1$。从这堆(第 $i$ 堆)中取走若干个石子,可以使 $x_i$ 的第 $k$ 位变成 $0$,然后因为这样一定会使 $x_i$ 变小,所以我们可以*确定第 $1$ 到 $k-1$ 位是 $0$ 还是 $1$。把 $sum$ 的每一位异或成 $0$ 即可。

  综上,所有 $x_i$ 的异或和 满足 SG 函数的转移性质,可以作为 SG 函数。

例题 3(Nimk)

  有 $n$ 堆石子,第 $i$ 堆数目分别为 $x_i$,$\text{A,B}$ 两人每次可以选最多 $k$ 堆石子,并从选中的每堆石子中取走任意多个,问 $\text{A}$ 先手是否有必胜策略。

sol

  Nimk 就是 Nim 游戏的一个简单扩展。

  先手存在必胜策略,当且仅当:将所有石子数转成二进制后,存在一个 $i$,使得所有二进制数的第 $i$ 位上 $1$ 的总数 $\mod (k+1)$ 不为 $0$。

  证明:

    当 Nimk 游戏的 SG 值为 $0$ 时,由于我们每次最多只能选 $k$ 堆,所以我们不能在同一二进制位上改变 $k+1$ 个值,因此在取一轮石子后 SG 值必然发生了改变。

    而对于一个 SG 值不为 $0$ 的局面,必然存在一种取石子方式,使其转移到必败局面。

    不妨设必胜局面下,$1$ 的个数 $\mod (k+1)$ 不为 $0$ 的最高二进制位上有 $m$ 个 $1$,设该二进制位为从低到高数第 $i$ 位,则将 $1$ 的个数改成 $k+1$ 的倍数 需要将该二进制位为 $1$ 的 $m$ 堆石子的数量都减 $2^(i-1)$。我们现在就取这 $m$ 堆。

    然后再找 $1$ 的个数 $\mod (k+1)$ 不为 $0$ 的最高二进制位,设该位上有 $n$ 个 $1$,并且记之前改变的 $m$ 堆石子在该位上有 $a$ 个 $1$ 和 $b$ 个 $0$($m,n,a,b$ 都是 $\mod (k+1)$ 后的值)。

    分情况讨论:

      1. $a\ge n$,则将之前 $m$ 堆石子中的 $n$ 个 $1→0$,这样不会改变更多堆石子

      2. $b\ge k+1-n$,则将之前 $m$ 堆石子中的 $k+1-n$ 个 $0→1$,这样不会改变更多堆石子

      3. $a\lt r$ 且 $b\lt k+1-r$,则将之前 $m$ 堆以外的 $m-a$ 堆的 $1→0$。那么此时改变的堆数为 $m+r-a → a+b+r-a → b+r$,又因为 $b+r\lt k+1-r+r → k+1$,所以我们改变的堆数 $m+r-a\lt k+1$,是合法的。

    重复上述操作,我们必然能使每一位上 $1$ 的个数 $\mod (k+1)$ 为 $0$,即转移到必败态。

  Nim 游戏相当于 Nimk 中 $k=1$ 的情况。

练习 1(uoj 266)

  给定一棵 $n$ 个节点的森林,每个连通块的根是块内编号最小的点。每个点有黑白两种颜色中的一种。$\text{A}$ 和 $\text{B}$ 轮流选择一个白点,将该点到根的路径上所有点都涂黑。谁无法操作谁输。问 $\text{A}$ 先手是否有必胜策略。

  题意等价于每次选择一个点,删除该点及其所有祖先。

sol

  下面的所有加法 $+$ 都表示不进位加法 $\text{xor}$。

  考虑树形 $\text{dp}$,根据题意设后继局面。

  对于这种树形题目,肯定是将以每个点为根的子树设为一个子游戏,然后以一个点为根的子树对应的子游戏的 $\text{SG}$ 值(下文简称为子游戏 $x$) 由这棵子树中若干个子游戏的 $\text{SG}$ 值转移来。

  正好题目要求记第一个涂黑的数,于是我们

    设 $f(x)$ 为以 $x$ 为根的子树的 $\text{SG}$ 值。

    设 $g(x,y)$ 为以 $x$ 为根的子树中,第一步涂黑了子树中的点 $y$ 后的 $\text{SG}$ 值。

    设 $sum(x) = \sum\limits_{y∈son(x)} f(y)$。

  不难发现, $g(x,y)$ 就是子游戏 $x$ 的一个后继局面集合

  考虑 $g$ 的转移。由于涂黑 $z$ 到子游戏 $x$ 的根节点 $x$ 路径上的所有点 相当于删掉这些点,于是剩下的每棵连通子树(即图中的所有三角)形成了一个新的子游戏。这些子游戏的 $\text{SG}$ 值之和就是子游戏 $x$ 的 $\text{SG}$ 值。

  终止局面:$$g(x,x)=sum(x)$$。即删掉这个点后,它的所有儿子子树形成了互不关联的子游戏,我们只需要取这些游戏的 $\text{SG}$ 值之和即可。

  一般局面:对于 $z≠x$ 的 $g(x,z)$,画个图(粗线表示一条链,链上的若干节点就不画了;三角表示一棵子树)

【基础操作】博弈论 / SG 函数详解

  不我们需要求所有三角子树对应的子游戏的 $\text{SG}$ 之和。

  那我们需要暴力跑一遍这条链吗?(其实暴力跑可以做到同一复杂度,但这样就没法优化做法了)

  不难发现,在 $x$ 的所有儿子中,$g(y,z)$ 已经帮我们记好了以 $y$ 为根的子树中这些三角的 $\text{SG}$ 值之和。

  于是有 $$g(x,z) = g(y,z)+\sum\limits_{y'\in son(x), z\notin subtree(y')} f(y') = g(y,z)+(\sum\limits_{y'\in son(x)} f(y'))+f(y)\space\space | \space\space z\in subtree(y)$$

  有人可能要问了:这不是 Nim 游戏,为什么一个局面的 $\text{SG}$ 值还是它后继子游戏的 $\text{SG}$ 值的异或和?

  其实对于所有简单组合游戏,我们可以将组成它的所有子游戏换成相应数目的一堆石子,这样所有的游戏都等价于 Nim 游戏。详情参考该论文的第 $7-8$ 页.

  upd:这篇论文据说不少结论都写错了,实际上其它游戏并不等价于 Nim 游戏。关于这题的异或原因见下:

    首先你需要普及一个知识 —— SG 定理:游戏和的 SG 函数等于各个游戏 SG 函数的 Nim 和(异或和)。

    然后我们对于这道题来尝试证明 SG 定理!

    考虑 Nim 游戏,它为什么能把每堆石子的数量异或起来,作为全局的 $\text{SG}$ 函数?关键原因是对于一堆数量为 $x$ 的石子,它可以变为 $0$ 到 $x-1$ 中的任意一个数!

    但我们仔细想想,为什么在 Nim 游戏是求每个子游戏(每堆石子)的数量的异或和,而 SG 定理是求每个子游戏的 SG 函数的异或和呢?

    之前是不是解释过,Nim 游戏中 $\text{SG}(x)=x$?

    所以 Nim 游戏也是求每个子游戏的数量的异或和嘛!

    所以对于这类博弈游戏,求每个子游戏的数量的异或和,关键在于对于任意一个子游戏,设其 $\text{SG}$ 值为 $\text{SG}(x)$,它必须能转移到 $\text{SG}$ 值为 $[0,\text{SG}(x)-1]$ 中整数的所有局面。

    那任意一个子游戏都是如此么?

    以这道题为例,一棵子树对应一个子游戏,我们考虑这个子游戏的 $\text{SG}$ 值的含义 —— 对该子游戏分解出的所有后继局面(每个后继局面都是一个子游戏集合)的 $\text{SG}$ 值求 $\text{mex}$。

    既然是求 $\text{mex}$,那不就说明这个子游戏包含 $\text{SG}$ 值为 $0,1,2,...,\text{SG}(x)-1$ 的后代么?

    然后我们重新梳理一下一堆子游戏放在一起的概念。

    【基础操作】博弈论 / SG 函数详解

    对于一棵树(你也可以假设其为初始局面),将一个点到根的路径删掉(图中加粗线条),就会分成很多个子游戏。分出的子游戏集合就是当前子游戏的一个后继局面。

    对于一个后继局面对应的子游戏集合 $S$,将一个子游戏 $A$ 中的一个点到根的路径删掉,$A$ 就又分成了若干个子游戏。我们用这若干个子游戏替换掉 $S$ 中的 $A$ 得到 $S'$,则 $S'$ 又是 $S$ 的后继。

    也就是说,局面一直是相对于整个游戏而言的

    而我们可以任选子树中的一个点,将它到根的路径删掉。选择的点不同,后继局面也不同,所以一个局面有很多后继局面。

    显然这个局面的 $\text{SG}$ 值就是所有后继局面的 $\text{SG}$ 值的 $\text{mex}$。

    但一个后继局面可能是很多子游戏组成的集合,该局面的 $\text{SG}$ 值就是每个子游戏的 $\text{SG}$ 值得异或和。

    这时不难发现,局面 -> 子游戏集合,$\text{SG}$ 值的转移只发生在不同的子游戏集合间。

    在 Nim 游戏中,子游戏集合的大小不变,相邻两个局面的子游戏集合只有一个数不同。

    在这个游戏中,子游戏集合的大小会变,但对于相邻两个局面,若前驱局面的 $\text{SG}$ 值不为 $0$,则前驱局面1一定可以选出一个子游戏,将其拆成若干个子游戏,使这个局面的 $\text{SG}$ 值为 $0$,而这就是前驱局面的某个后继局面;若前驱局面的 $\text{SG}$ 值为 $0$,由于集合中每个子游戏的 $\text{SG}$ 值都是该子游戏的所有后继局面的 $\text{SG}$ 值的 $\text{mex}$,所以该集合中不存在一个子游戏 $A$,使得这个子游戏存在一个后继局面 $B$,满足 $\text{SG}(A)=\text{SG}(B)$,进而得出该前驱局面的后继局面的 $\text{SG}$ 值一定会变为非 $0$。

    不难发现这种子游戏集合间的转移满足 $\text{SG}$ 函数的转移要求。

    实际计算时,我们从终止局面出发, $\text{dp}$ 出每个子游戏的 $\text{SG}$ 值即可,因为你显然不可能记下每个局面对应的子游戏集合,而我们只需要知道一个子游戏集合中的每个子游戏的 $\text{SG}$ 值,而一个子游戏是原树的一个子树,故只有 $n$ 个。再结合这题的 $\text{dp}$ 方式,就只有 $n^2$ 种实际存在的局面了。

    Q.E.D

  然后考虑 $f$ 的转移,由于 $g(x,i)$ 都是子游戏 $x$ 的后继局面,所以 $f(x) = \text{mex}(g(x,i)\space |\space i\in subtree(x))$。

  有了 $f$ 和 $g$ 的转移,暴力 $\text{dp}$ 是 $O(n^2)$ 的。

  code

  下面考虑数据结构优化 $\text{dp}$。

  用一棵 $\text{01trie}$ 维护每个点 $x$ 的数组 $g_x(z)$。

  则 $g_x$ 由所有 $g_y$ 整体异或 $f(y)$ 后合并起来 再整体异或 $\sum\limits_{y\in son(x)} f(y)$ 得到(也可以直接对每个 $g_y$ 整体异或 $f(y) + \sum\limits_{y\in son(x)} f(y)$)。

  然后我们需要对 $g_x$ 求 $\text{mex}$ 得到 $f(x)$。

  $\text{01trie}$ 可以轻松维护整体异或一个值、求 $\text{mex}$。对于整体异或一个值,打 $\text{tag}$ 记录以该点为根的子树要异或的值 $x$ ,若 $x$ 在该点对应的二进制位为 $1$ 则交换该点的左右儿子;对于求 $\text{mex}$,直接在 $\text{trie}$ 树上二分,若左子树未满则往左走,满了则往右走。

  由于 $\text{SG}$ 值 $\le n$,故总复杂度为 $O(n\log n)$。

  code

update:

  我在 $\text{uoj}$ 翻 $\text{60pts}$ 代码时,看到了一个奇怪的代码

  不难发现,他在 $\text{dfs2}$ 中写了这么一句:if(FLAG) tot[0]+=coef;

  这显然有问题,因为 $\text{dfs2}$ 实质上是在枚举 $g(x,z)$ 的 $z$,而上面这句没有对应的 $z$,对于叶子节点也不应该有任何特殊操作,不知道作者是怎么想的居然能写出这么明显的问题。

  他这么写,相当于默认任何状态都有一个值为 $0$ 的后继状态。当时我就跟 scb 神仙讨论了一下,他也不知道这是什么道理。于是我们在 ezoj 上翻了一下这道题的简化版 —— 保证 $n$ 个点由 $n-1$ 条边连通成一棵树,结果发现那题的数据全是 $\text{Alice}$ 必胜

  回来看了下这道题,发现在只有一棵连通树的情况下,$\text{SG}$ 值一定不为 $0$,即 $\text{Alice}$ 必胜。样例中唯一一组 $\text{Bob}$ 赢的数据还是两个不相连的单点。

  我们很疑惑,于是尝试构造了几组一棵连通树的数据,很快发现构造出的数据的 $\text{SG}$ 值全不为 $0$……

  scb 帮忙上交友群问了一下证明·,发现很简单……

  对于一棵连通树,让 $\text{Alice}$ 先选根节点,若去掉根节点后的局面为必败态,那 $\text{Alice}$ 当然就赢了;

  若为必胜态,则 $\text{Bob}$ 可以通过选择某个点让 $\text{Alice}$ 必败,也就是让 $\text{Bob}$ 必胜。但不难发现由于 $\text{Alice}$ 选的点是根,所以一定是 $\text{Bob}$ 选的点的祖先,在选择某个点之前选择它的祖先 是无用操作(因为一次操作是选择某个点,将其和所有祖先涂黑),故让 $\text{Alice}$ 一开始不选根节点 而选这个点,$\text{Alice}$ 就必胜了。

  这个证明思路和一个类似的游戏很像 —— $n\times m$ 的棋盘,每次去掉一个格子及其右下角所有格子。

后记

  这玩意可能不怎么考,不要过度痴迷。