ICG 游戏博弈问题与 SG 定理
ICG 游戏
定义
ICG 游戏是博弈游戏的一种,其定义如下:
- 游戏由两人参加,两人轮流做出决策
- 当有一人无法决策即无论如何都必败时对手胜出,且 ICG 游戏一定会在有限步内完成,游戏没有平局
- 游戏的状态转移是单向的,同一个状态只能达到一次
必胜点和必败点
必胜点 N ( Next ) 和必败点 P ( Previous ) 描述的是某个游戏状态当前的胜负。
若当前状态为必胜点 N ,则先手必胜,反之,若当前状态为必败点 P ,则先手必败。
可能到这里为止大家还是会觉得比较抽象,所以我们给出一个实际例子:
假设有一堆石头,两人轮流从这堆石头中取走 1 ~ 5 块石头,初始状态下有 n 块石头,问 n 为何值时先手必胜?
先说结论:n % 6 != 0
时先手必胜。
原因十分简单,若 n 不是 6 的倍数,则先手一定可以取走 1 ~ 5 块内的石头使得取走石头后这堆石头的数量能被 6 整除,此后,对手只要取走 m 块石头,我们就取走 6 - m 块石头,可以保证我们每次取完后石头的数量都是 6 的倍数。如此一来,最后的石头一定是被我们取走。
于是,我们可以得到石头数量 n 对应的 NP 状态:
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ... |
---|---|---|---|---|---|---|---|---|---|---|---|
state | P | N | N | N | N | N | P | N | N | N | ... |
在这里,我们不难得出结论:
- 所有必胜点必然可以在一步操作内转移到必败点
- 所有必败点无论如何操作只能转移到必胜点
SG 定理
SG 是 Sprague-Grundy 的缩写,SG 定理是处理 ICG 博弈问题的重要方法,在讲解其使用之前,我们先简要介绍一下 SG 函数的定义。
SG 函数
首先我们定义 \(mex\) ( minimal excludant ) 运算,\(mex(F)\) 即表示不属于非负整数集 \(F\) 中最小的元素:
例如: \[ \begin{array}{} mex(\{1, 2, 3\}) = 0 \\ mex(\{0, 1, 3, 4\}) = 2 \\ mex(\emptyset) = 0 \end{array} \] 什么是 SG 值?
SG 值是一种通过递归定义的值,它一般情况下是一个非负整数,可以用来描述游戏状态是必胜点还是必败点,假设游戏状态 \(V_i\) 的 SG 值为 \(SG(V_i)\) ,那么其状态转移方程如下: \[ SG(V_i) = mex(\{SG(V_j) \ | \ V_i \rightarrow V_j \}) \] 其数值上等于与 \(V_i\) 所有后继状态的 SG 值不相等的最小非负整数。
基于此,我们得到一条重要结论:SG 值不为 0 的状态为必胜点,SG 值为 0 的状态为必败点。
这个结论很好证明:若 SG 值不为 0,说明该状态一定能一步转移到 SG 值为 0 的状态,即可以一步转移到必败点,所以该状态一定为必胜点;反之,若 SG 值为 0,则该状态无法一步转移到必败点,只能转移到必胜点或者无法决策,故该点一定为必败点。
我们还是用上述的取石头问题来举例说明,则不同石头数量 n 对应的 SG 值如下:
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
SG(n) | 0 | 1 | 2 | 3 | 4 | 5 | 0 | 1 | 2 | 3 | 4 |
\[ \begin{array}{} SG(0) = mex(\emptyset) = 0 \\ SG(1) = mex(\{0\}) = 1 \\ SG(2) = mex(\{0, 1\}) = 2 \\ SG(3) = mex(\{0, 1, 2\}) = 3 \\ SG(4) = mex(\{0, 1, 2, 3\}) = 4 \\ SG(5) = mex(\{0, 1, 2, 3, 4\}) = 5 \\ SG(6) = mex(\{1, 2, 3, 4, 5\}) = 0 \\ ... \newline SG(10) = mex(\{5, 0, 1, 2, 3\}) = 4 \\ ... \end{array} \]
SG 定理详解
现在我们已经知道了 SG 函数的定义,那 SG 定理又是什么呢?
什么是 SG 定理 ?
SG 定理指的是若一个 ICG 博弈游戏的游戏状态可以分为多个子状态,且子状态互相独立,则该游戏状态下的 SG 值等于所有子状态的 SG 值的异或值。
这又是什么意思呢?别急,我们还是用取石头的例子来说明:
假设现在有 \(k\) 堆石头,每堆石头有 \(n_i(i = 1, 2, ...,k)\) 块石头 ,两个人轮流从每一堆石头中取走 \([1, m]\) 块石头,先取完所有石头的一方获胜。我们设此刻游戏状态的 SG 值为 \(SG((n_1, n_2, ..., n_k))\) ,由 SG 定理可得: \[ SG((n_1, n_2, ..., n_k)) = SG(n_1) \oplus SG(n_2) \oplus ... \oplus SG(n_k) \]
- \(SG((n_1, n_2, ..., n_k)) \neq 0\) :先手胜
- \(SG((n_1, n_2, ..., n_k)) = 0\) :先手败
以上就是完整的 SG 定理了。
SG 定理的合理性
为什么 SG 定理会与位运算的异或有关呢?它们是如何联系上的?为什么这种计算是合理的呢?
以下我们给出简要的证明:
根据 SG 值的定义,必败点的 SG 值一定为 0,对于此题而言,游戏的终点就是所有的石头被取完,此时 SG 值是 k 个 0 的异或值,显然为 0。
若当前的 SG 值不为 0,我们假设: \[ SG((n_1, n_2, ..., n_k)) = {001010..}_2 \] 我们找到该 SG 值数值为 1 的最高位,由异或运算符的性质,必然存在奇数个子状态的 SG 值该位为 1,我们不妨假设其中一个子状态对应的 SG 值为 \(SG_0\) ,由 SG 值的定义,该状态一定可以一步之内转变为任何 SG 值小于 \(SG_0\) 的状态,\(SG_0\) 对应母状态下数值为 1 的最高位的值也为 1,我们让其变为 0,然后从这一位开始之后全部位取反,则一定可以将母状态的 SG 值变为 0。
0 1 1 0 0 0
0 1 0 1 0 1
0 1 1 0 1 0
如上,我们将第二个子状态 的 SG 值转移到 0 0 0 1 1 1,就将母状态的 SG 值转化为 0 了
0 1 0 1 1 1
0 0 0 1 1 1
0 1 0 1 0 1
0 0 0 0 0 0
反之,如果母状态的 SG 值为 0,则改变任何一个子状态,由于异或运算的性质,母状态的 SG 值一定无法维持为 0。
而根据 ICG 博弈游戏的定义,游戏一定会在有限步内完成,故所有子状态 SG 值的异或运算不为 0 的母状态一定是必胜点。
实际应用
Fibonacci again and again
Problem Description 任何一个大学生对菲波那契数列(Fibonacci numbers)应该都不会陌生,它是这样定义的: F(1) = 1; F(2) = 2; F(n) = F(n - 1) + F(n - 2) ( n >= 3 ); 所以,1, 2, 3, 5, 8, 13, ... 就是菲波那契数列。 今天,又一个关于 Fibonacci 的题目出现了,它是一个小游戏,定义如下:
- 这是一个二人游戏;
- 一共有 3 堆石子,数量分别是 m, n, p 个;
- 两人轮流走;
- 每走一步可以选择任意一堆石子,然后取走f个;
- f 只能是菲波那契数列中的元素 ( 即每次只能取1,2,3,5,8 … 等数量 );
- 最先取光所有石子的人为胜者;
假设双方都使用最优策略,请判断先手的人会赢还是后手的人会赢。
Input 输入数据包含多个测试用例,每个测试用例占一行,包含 3 个整数 m, n, p ( 1 <= m, n, p <= 1000 )。 m = n = p = 0 则表示输入结束。
Output 如果先手的人能赢,请输出“Fibo”,否则请输出“Nacci”,每个实例的输出占一行。
输入样例
1
2
31 1 1
1 4 1
0 0 0输出样例
1
2Fibo
Nacci
分析:
本题所描述的游戏就是一种 ICG 博弈,且三堆石头互不影响,所以我们可以直接使用 SG 定理求解,再加上记忆化 DFS 优化,很容易就能求解此问题。废话不多说,直接上代码😎。
代码:
1 |
|