博弈论:ICG 与有向图游戏 · SG 函数
博弈论:ICG 与有向图游戏 · SG 函数
1. 有向图游戏(Directed Graph Game)
定义:一个有向图游戏由一张有向图 \(G=(V,E)\) 描述:
- 每个结点 \(x\in V\) 代表一个局面(position / state);
- 每条有向边 \((x,y)\in E\) 代表从局面 \(x\) 出发一步合法操作可以到达局面 \(y\);
- 游戏的进行,就是从某个起点结点开始,沿有向边一步步走。
终止规则(Normal Play):轮到某玩家时,若当前结点没有出边(出度为 \(0\)),则该玩家无法行动,判负。
有限性:竞赛中的博弈必在有限步内结束,因此图 \(G\) 无环(即 \(G\) 是有向无环图,DAG)。无环保证可以从"终点"逆推,对每个结点赋予确定的胜负属性。
感性理解:任何一个"两人轮流走、走不动就输"的游戏,都能画成一张 DAG——这正是博弈论可计算的根本原因。
2. ICG 是有向图游戏的公平特例
一个游戏被称为公平组合游戏(Impartial Combinatorial Game, ICG),须同时满足:
- 两人轮替行动;
- 信息完全公开、无随机因素(没有骰子、暗牌、概率);
- 有限终止:任意一局有限步内必结束,且无法行动者负。
"公平"的含义:从同一局面出发,双方可用的合法操作集合完全相同——与"轮到谁"无关。
这一点至关重要:正因为操作集合不随玩家改变,一个 ICG 才只需要一张有向图来建模(而非给两个玩家各画一张)。所以:
ICG = 操作集合与玩家无关的有向图游戏。
凡是 ICG,就一定能套用第 3、5 节的 N/P 态与 SG 理论。
- 典型 ICG:Nim、取石子、巴什、威佐夫、翻硬币。
- 非 ICG:围棋 / 象棋(双方操作集不同)、大富翁(有骰子)、扑克(有暗牌)。
3. 必胜态与必败态(N / P-position)
在 DAG 上,对每个结点定义两类胜负属性:
- P-position(必败态 / Previous-player winning):当前轮到行动的玩家必败(假设对手不犯错)。
- N-position(必胜态 / Next-player winning):当前轮到行动的玩家有必胜策略。
自底向上的递推法则(从出度为 \(0\) 的终止结点往回推):
- 终止结点(出度 \(0\))是 P-position——轮到你却无路可走,你输。
- 一个结点是 N-position \(\iff\) 它至少有一条出边指向 P-position(你走一步把对手送进必败态)。
- 一个结点是 P-position \(\iff\) 它的所有出边都指向 N-position(无论你怎么走,对手都进入必胜态)。
二染色定理:上述规则把整张 DAG 的每个结点恰好染成 N 或 P 之一,且不产生矛盾。
证明用数学归纳 / 拓扑序:按拓扑序从小到大处理结点,终止结点已定为 P;每个非终止结点的属性仅由其后继(拓扑序更小的结点)决定,归纳假设保证后继属性已确定,故当前结点属性唯一确定。
注:P 是"怎么走都赢不了",N 是"至少有一条路能赢"。
4. Nim 游戏:原型示例
模型:有 \(k\) 堆石子,第 \(i\) 堆有 \(a_i\) 个。两人轮流选某一堆取走任意正整数个(至少 \(1\),至多整堆),取走最后一颗者胜。
"游戏的和"视角:单独的"一堆石子"就是一个最简单的有向图游戏(结点 \(0,1,\dots,a_i\),从 \(x\) 可走到任意 \(0\le y<x\))。Nim = \(k\) 个这样的单堆游戏的和(每回合任选一堆走一步)。
Bouton 定理(1901):
其中 \(\oplus\) 为按位异或。即:异或和为 \(0\) 是必败态(P),非 \(0\) 是必胜态(N)。
证明:记总异或和 \(S=a_1\oplus\cdots\oplus a_k\)。
-
(a) 终局 \(S=0\) 为 P:所有堆为空 \(\Rightarrow S=0\),且确实无合法操作,符合第 3 节终止结点定义。
-
(b) \(S\neq 0\) 时存在一步使其变 \(0\)(\(\Rightarrow\) 是 N-position):
设 \(S\) 的二进制最高位为第 \(b\) 位(即该位为 \(1\))。必存在某堆 \(a_i\) 在该位也为 \(1\)——否则所有 \(a_i\) 第 \(b\) 位都是 \(0\),异或和该位不可能为 \(1\)。取这一堆,令\[a_i' = a_i\oplus S \]因为 \(a_i\) 与 \(S\) 在第 \(b\) 位都是 \(1\),异或后第 \(b\) 位变 \(0\),故 \(a_i'<a_i\)。于是可从第 \(i\) 堆取走 \(a_i-a_i'\) 个使其变为 \(a_i'\)。此时新异或和
\[S' = S\oplus a_i\oplus a_i' = S\oplus a_i\oplus(a_i\oplus S)=0 \]即总能把异或和变成 \(0\),且操作合法(\(a_i'<a_i\))。
-
(c) \(S=0\) 时任何一步都使其变非 \(0\)(\(\Rightarrow\) 是 P-position):
若从某堆 \(a_i\) 取成 \(a_i'<a_i\),新和 \(S'=S\oplus a_i\oplus a_i'=a_i\oplus a_i'\)。由于 \(a_i'\neq a_i\),有 \(a_i\oplus a_i'\neq 0\),故 \(S'\neq 0\)。即任何操作都会离开 \(0\) 态。
(b)(c) 合起来:凡 \(S\neq 0\) 都能走到 \(S=0\);凡 \(S=0\) 都只能走到 \(S\neq 0\)。配合终局,整张图按异或和是否为 \(0\) 精确染色,定理得证。
胜负策略:面对 \(S\neq 0\),按 (b) 的构造找到那堆并取;此后对手每次把和搞成非 \(0\),你总能再变回 \(0\),最终对手面对 \(S=0\) 的空局。
5. SG 函数:把任意有向图游戏映射到 Nim
Nim 的"异或判胜负"极其优美,但多数游戏的单堆不是"取任意个"那么简单。SG 函数的强大之处在于:它把任意一个 ICG 局面映射成一个"等价 Nim 堆的大小",从而让所有 ICG 都能套用 Nim 的异或规则。
5.1 mex 运算
对非负整数集合 \(S\subseteq\mathbb{N}_0\),定义
即"最小的非负整数排斥值"。示例:
- \(\operatorname{mex}(\{0,1,2\})=3\)
- \(\operatorname{mex}(\{1,2,4\})=0\)
- \(\operatorname{mex}(\varnothing)=0\)
5.2 SG 函数的定义
对每个结点 \(x\),定义其 SG 值:
即:\(x\) 的 SG 值 = 它所有直接后继的 SG 值的 mex。
- 若 \(x\) 是终止结点(无后继),则集合为空,\(\operatorname{mex}(\varnothing)=0\),故 \(SG(x)=0\)。这恰好与"终止局面是 P-position"吻合。
- 由第 3 节的递推,可归纳得到核心判定:
5.3 感性理解
\(SG(x)\) 表示"该局面在 Nim 中等价于一个大小为 \(SG(x)\) 的堆"。\(SG=0\) 就像空堆——你在这个局面上已经榨不出任何优势。
6. 游戏的和与 SG 定理(核心)
游戏的和(Sum of Games):同时摆着若干个互相独立的子游戏 \(G_1,G_2,\dots,G_k\)。每回合玩家任选一个子游戏走一步(其余不动),直到所有子游戏都无法行动。这就是组合游戏的"和"。
Sprague–Grundy 定理(SG 定理,1935 / 1939):
即:和的 SG 值 = 各子游戏 SG 值的异或和。
推论:任意 ICG 都等价于一个 Nim 实例——把每个子游戏的 SG 当作一个 Nim 堆的大小,整体胜负由这些"堆"的异或和决定。于是求解任意复杂 ICG 的总思路是:
- 把原游戏拆成若干独立子游戏;
- 对每个子游戏算出(或递推 / 打表)其 \(SG\) 值;
- 全部异或;结果非 \(0\) 则先手必胜,为 \(0\) 则必败。
7. SG 定理的严格证明
对"和的规模"(子游戏个数与各自结点的拓扑序)做归纳。先证两个引理(对单个结点 \(x\),\(g=SG(x)\)):
- 引理 (i):对任意 \(0\le t<g\),存在后继 \(y\)(即 \((x,y)\in E\))使 \(SG(y)=t\)。
证明:由 \(g=\operatorname{mex}\{SG(y)\mid(x,y)\in E\}\),所有小于 \(g\) 的非负整数都出现在后继 SG 集合中,故必存在这样的 \(y\)。 - 引理 (ii):不存在后继 \(y\) 使 \(SG(y)=g\)。
证明:若某后继 SG 等于 \(g\),则 \(g\) 就不在"最小排斥值"的位置上,与 \(g\) 是 mex 矛盾。
现在考察和游戏 \(G=G_1+\cdots+G_k\),记 \(g_i=SG(G_i)\),并记当前组合值 \(g=g_1\oplus\cdots\oplus g_k\)。
-
情形 A:\(g=0\)。任意一步必然改变某一个子游戏 \(G_i\)(从 SG 值 \(g_i\) 变到某个 \(g_i'\neq g_i\))。新组合值
\[g'=g\oplus g_i\oplus g_i'=g_i\oplus g_i'\neq 0\quad(\text{因 }g_i\neq g_i') \]即从 \(g=0\) 出发的任何一步都走到 \(g\neq 0\)。故 \(g=0\) 对应 P-position。
-
情形 B:\(g\neq 0\)。设 \(g\) 的最高位为第 \(b\) 位。必存在某个 \(i\) 使 \(g_i\) 第 \(b\) 位为 \(1\)(理由同第 4 节 (b))。令
\[g_i'=g_i\oplus g \]则 \(g_i'<g_i\)(最高位被清零)。因为 \(g_i'<g_i=g_i\) 且 \(g_i=SG(G_i)\),由引理 (i),在子游戏 \(G_i\) 中存在一步从当前局面走到 SG 值为 \(g_i'\) 的局面。走这步后新组合值
\[g'=g\oplus g_i\oplus g_i'=g\oplus g_i\oplus(g_i\oplus g)=0 \]即从 \(g\neq 0\) 出发,必存在一步走到 \(g=0\)。故 \(g\neq 0\) 对应 N-position。
情形 A、B 与第 3 节 N/P 判定、第 4 节 Nim 证明逐字平行。归纳闭环,证得和的 SG 恰等于各分量 SG 的异或和,即 SG 定理成立。
一句话记忆:SG 是"局面对 Nim 的等价堆高";多个独立游戏相加用异或;判胜负看总 SG 是否为 \(0\)。
8. 理论示例(SG 计算演示)
8.1 受限单堆取子(S-Nim 思路)
模型:一堆共 \(x\) 个,每次只能取集合 \(S=\{s_1,s_2,\dots\}\) 中的数量(\(s\le x\))。这是单堆有向图游戏,SG 直接递推:
示例:取 \(S=\{1,2,3\}\),手算前若干项:
| \(x\) | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|---|
| \(SG(x)\) | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 |
规律:\(SG(x)=x\bmod 4\),周期为 \(4\)。若有多堆,总 SG 为各堆 \(SG\) 的异或;总 SG \(\neq 0\) 则先手胜。
8.2 用「有向图 + SG」统一重释
- 巴什博弈(一堆 \(n\) 个、每次取 \([1,m]\) 个):即 \(S=\{1,2,\dots,m\}\),递推得 \(SG(n)=n\bmod(m+1)\)。
- 标准 Nim(一堆可取任意正数量):即 \(S=\{1,2,\dots\}\),递推得 \(SG(n)=n\)——单堆的 SG 就是堆本身的大小!这也说明"多堆 Nim 异或"正是 SG 定理的特例(\(SG=\bigoplus a_i\))。
8.3 SG 的计算方法
- 记忆化搜索:
dfs(x)返回 \(SG(x)\),用mex合并后继;适合状态空间有结构、可递归的问题。 - 打表找周期:许多受限取子游戏的 SG 呈短周期,先暴力算前若干项观察周期,再利用周期回答大询问。
9. C++ 代码模板
9.1 裸 Nim(异或判胜负)
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n; cin >> n;
int sg = 0, x;
while (n--) { cin >> x; sg ^= x; } // 总 SG = 各堆异或
cout << (sg ? "First" : "Second") << '\n';
return 0;
}
9.2 单堆 SG 记忆化 / 打表(通用框架)
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAXN = 10005;
int S[MAXN], m; // 可取步长集合(已排序去重)
int sg[MAXN]; // -1 表示未计算
bool vis[MAXN];
int getSG(int x) {
if (sg[x] != -1) return sg[x];
memset(vis, 0, sizeof(vis));
for (int i = 0; i < m; i++) {
if (S[i] <= x) vis[getSG(x - S[i])] = true;
else break;
}
for (int i = 0; ; i++) // mex
if (!vis[i]) { sg[x] = i; break; }
return sg[x];
}
// 初始化:memset(sg, -1, sizeof(sg));
// 总 SG:对各堆 a[i] 求 getSG(a[i]) 后全部异或
9.3 游戏的和(多子游戏异或)
// 各子游戏独立,分别算出 SG 值后异或
int total = 0;
for (int i = 0; i < k; i++) total ^= sgOfGame_i(state_i);
// total != 0 ⇒ 先手必胜;total == 0 ⇒ 先手必败
10. 总结与易错点速查表
10.1 判定流程(博弈题思路)
- 它是 ICG 吗?(两人、信息公开、无随机、有限终止)不是则 SG 不直接适用。
- 能否拆成若干独立子游戏?能 \(\Rightarrow\) 各算 SG 再异或(SG 定理)。
- 单局面能否直接递推 \(SG=\operatorname{mex}\{\text{后继 }SG\}\)?能 \(\Rightarrow\) 记忆化 / 打表。
- 是否匹配已知闭式模型(Nim / 巴什 / 威佐夫 / …)?匹配则用对应结论。
- 是否 Misère(取最后者负)?是 \(\Rightarrow\) 套 Misère 规则(仅全 \(1\) 堆时反转结论)。
10.2 易错点
| 易错点 | 说明 |
|---|---|
| 忘记"游戏的和"要异或各 SG | 多堆 / 多子游戏绝大多数是异或,不是相加 |
mex 写错 |
vis 数组要覆盖 SG 上界;SG 上界 \(\le\) 后继种类数 |
| 把有环图当 DAG | ICG 必须有限终止,才能保证 SG 良定义;出现环说明模型建错 |
| 混淆 Normal 与 Misère | 仅"所有堆都是 \(1\)"时 Misère 反转结论,其余同 Nim |
| SG 定义里"后继"枚举不全 | 必须把所有合法一步都列进 mex 集合 |
| 误以为 \(SG(x)\) 就是"剩余步数" | SG 是等价 Nim 堆高,不是剩余可走步数 |
10.3 一句话总纲
任何公平组合游戏都能等价成 Nim。算出每个子游戏的 SG(= 等价堆高),全部异或;异或和非 \(0\) 先手必胜,为 \(0\) 先手必败。
而有向图游戏,正是这一切的统一语言。
原创·转载请注明出处
✦
浙公网安备 33010602011771号