本文主要介绍acm中有关博弈论的基础知识点,意在梳理博弈论学习的总体框架与基本逻辑,使读者和作者都能够对博弈论的思维方式有更深入的理解。
问题:有两个绝顶聪明的人在玩取石子游戏,假设最初有n个石子,每人可以轮流取1~m范围内的石子,如果没有石子可取就失败,问先手胜还是后手胜。
巴什博奕属于博弈论中最基础的问题,但从该问题我们往往能够扩展得出许多研究博弈论的基础方法。
从特殊到一般:如果不清楚如何解决这个问题,不妨考虑最简单的情况。
局面一:当 n ≤ m \mathbf{n\le m} n≤m的时候,显然先手可以直接取走所有的石子,先手必胜。
局面二:当 n = m + 1 \mathbf{n=m+1} n=m+1的时候,先手无法一次性取完所有石子,但是先手取了1~m颗石子以后石子数量就满足 n ≤ m \mathbf{n\le m} n≤m,这是局面一的情况,根据局面一的结论,局面一的先手必胜,也就是局面二的后手必胜,所以局面二的先手必输。
局面三:当 m + 1 < n ≤ m + 1 + m \mathbf{m+1
局面四:当 n = m + 1 + m + 1 \mathbf{n=m+1+m+1} n=m+1+m+1的时候,由于无论如何先手也只能将石子取为 m + 1 < n ≤ m + 1 + m \mathbf{m+1
…
局面n:…
归纳与总结:很容易发现一个规律,当 ( m + 1 ) ∣ n \mathbf{(m+1)|n} (m+1)∣n,先手必输,如果想直接证明这一点,不妨设 n = k ∗ ( m + 1 ) + r ( r < m + 1 ) \mathbf{n=k*(m+1)+r\quad (r
因此可以得出关于巴什博奕的结论:当 ( m + 1 ) ∣ n \mathbf{(m+1)|n} (m+1)∣n先手必败,否则先手必胜。
扩展一:在经典巴什博奕的基础上,假设拿走最后一颗石子的一方输掉,那么结果如何?
拿走最后一颗石子的一方输掉,可以转化为拿走前n-1颗石子中的最后一颗的一方胜利,这样也就转化为n-1情形下的经典巴什博奕,那么结论也很容易得出:当 ( m + 1 ) ∣ ( n − 1 ) \mathbf{(m+1)|(n-1)} (m+1)∣(n−1)先手必败,否则先手必胜。
扩展二:假设每次可以拿的石子数为[a,b],当石子数小于a的时候不能拿,不能拿石子的一方失败,那么结果如何?
这时候问题变得稍微复杂一些,设 n = k ⋅ ( a + b ) + r ( 0 ≤ r < a + b ) \mathbf{n=k\cdot (a+b)+r(0\le rn=k⋅(a+b)+r(0≤r<a+b),然后分如下情况进行讨论:
1. r = 0 \mathbf{r=0} r=0,此时后手的策略很简单,假设每回合先手拿 x ( a ≤ x ≤ b ) \mathbf{x(a\le x\le b)} x(a≤x≤b)颗石子,后手则拿 a ≤ a + b − x ≤ b \mathbf{a\le a+b-x\le b} a≤a+b−x≤b颗石子,这样就能保证后手拿走最后一颗石子,取得胜利。因此这种情况下先手必败。
2. r ∈ ( 0 , a ) \mathbf{r\in (0,a)} r∈(0,a),由于这r个石子最终谁也拿不了,故类似局面1,先手必败。
3. r ∈ [ a , b ] \mathbf{r\in [a,b]} r∈[a,b],如果先手拿走r颗石子,那么后手必定就面临局面1,也就是说先手必胜。
4. r ∈ ( b , a + b ) \mathbf{r\in (b,a+b)} r∈(b,a+b),这时候先手拿走b颗石子,就变成了局面2,也就是说先手必胜。
综上所述,先手必胜当且仅当 r ∈ [ a , a + b ) \mathbf{r\in [a,a+b)} r∈[a,a+b)。
扩展三:在扩展二的基础上,不能拿石子的一方胜利,那么结果如何?
类比于扩展一的思路,将扩展二结论中的n替换为n-a即可。
扩展四:在扩展二的基础上,假设当石子数小于a的时候必须一次性拿完,那么结果如何?
设 n = k ⋅ ( a + b ) + r ( 0 ≤ r < ( a + b ) ) \mathbf{n=k\cdot (a+b)+r(0\le r<(a+b))} n=k⋅(a+b)+r(0≤r<(a+b)),这里直接给出结论(证明还没想好):
当且仅当 r ∈ [ 1 , a ) ∪ [ a , b ] \mathbf{r\in [1,a)\cup[a,b]} r∈[1,a)∪[a,b]时先手必胜。
扩展五:在扩展四的基础上,假设不能拿石子的一方胜利,问结果如何?
同扩展三,将扩展四结论中的n替换为n-a即可。
问题:有两个绝顶聪明的人在玩取石子游戏,假设有n堆石子,每个人可以轮流选择某一堆然后从中拿走任意数量的石子(不能为0),如果没有石子可取就失败,问先手还是后手胜利。
通过前面的巴什博奕的思考过程我们可以有所启发,首先是利用先手和后手的概念在讨论各个局面的时候显得并不是那么方便,因此我们可以引入必胜局面和必败局面的概念,这对于后续其他博弈游戏的讨论也将大有裨益。
首先明确一点,在必胜局面下先手必胜,在必败局面下先手必败。
必胜局面(N-position):存在一种合法操作使转化为必败局面。
必败局面(P-position):任意一种合法操作都使其转化为必胜局面。
这上面的两个概念很容易理解,可以结合前面的巴什博奕进行思考。
有了这两个概念,我们所有工作的重心就变成了寻找必胜局面和必败局面。而在本题中的必胜局面和必败局面并不是那么容易寻找,我们先提前给出结论:
当且仅当所有堆石子数的异或和为0的时候是必败局面,其他局面都是必胜局面。
要想证明上述结论,我们只需要看它是否满足必胜局面和必败局面的定义即可。
1.当所有堆石子数为0的时候,满足为必败局面且异或和为0。
2.当所有堆石子数异或和不为0的时候,假设异或和为y,则必定存在一堆石子数量为x,对y的最高位的1有贡献,我们将x替换为 x ⊕ y \mathbf{x\oplus y} x⊕y,那么新的异或和变为了 ( x ⊕ y ) ⊕ ( x ⊕ y ) = 0 \mathbf{(x\oplus y)\oplus(x\oplus y)=0} (x⊕y)⊕(x⊕y)=0,再看操作是否合法,由于x与y的最高位一样,因此 x ⊕ y \mathbf{x\oplus y} x⊕y 一定会把最高位抵消掉,也就是说 x ⊕ y < x \mathbf{x\oplus y
3.当所有堆石子异或为0且存在一堆石子不为0的时候,不管怎么拿石子,一定会导致所有堆石子异或和不为0,因此对于任意合法操作都一定使必败局面转话为必胜局面,也满足条件。
综上所述,“当且仅当所有堆石子数的异或和为0的时候是必败局面,其他局面都是必胜局面。” 的结论成立。
问题:有两个绝顶聪明的人在玩取石子游戏,假设有n堆石子,每个人可以轮流选择某一堆然后从中拿走任意数量的石子(不能为0),取走最后一颗石子的一方失败,问先手还是后手胜利。
反尼姆博弈与尼姆博弈唯一的差别在于输赢的判定反了一下,但结论并不是反一下就可以套过来用的。
一般要得出结论需要不断地从特殊到一般化,找规律和不断地总结,因此我们还是先给出结论再证明结论。
必胜局面只有两种情况:1.所有堆的石子数都为1并且所有堆石子数异或和为0。
2.存在一堆石子数大于1并且所有堆石子数异或和不为0
要想证明结论可以考虑如下四种局面。
1. 当所有堆的石子数都为1的时候。
(1) 若堆数为偶数(此时所有堆石子数异或和为0),后手必定拿完最后一堆石子,因此是必胜局面;
(2) 若堆数为奇数堆,同理可得是必败局面。
2. 当只有一堆石子数大于1的时候(此时所有堆石子数异或和必不为0)。
(1) 如果总共有偶数堆石子,那么先手可以将石子数大于1的堆拿完从而剩下奇数个石子数为1的堆,这样就回到了局面1-(2),这是一个必败局面,因此 2-(1) 是一个必胜局面;
(2) 如果总共有奇数堆石子,那么先手可以将石子数大于1的堆拿到只有一颗石子从而变成就数个石子数为1的堆,这样又回到了局面 1-(2),因此 2-(2) 也是一个必胜局面。
综上所述局面2是一个必胜局面。
3. 当有大于1堆的石子数都大于1且所有堆石子数异或和不为0的时候。类似于普通尼姆博弈的策略,我们设这个异或和为y,然后找到对y的最高位的1具有贡献的堆,设其石子数为x,然后让x变为 x ⊕ y \mathbf{x\oplus y} x⊕y,这样就能够将异或和不为0的局面(必胜局面)转化为异或和为0的局面(必败局面)。并且由于同时存在两堆及以上石子数大于1,并且一次性只能操作一堆石子,所以转化为异或和为0的局面的时候也必定存在至少两堆的石子数大于1(一堆石子数大于1的局面必定不可能异或和为0)。因此必胜局面可以转化为必败局面。
4. 当有大于1堆石子都大于1且所有堆石子数异或和为0的时候。类似于普通尼姆博弈,这时候拿任意一堆的任意数量的石子都会导致异或和不为0且至少存在一堆石子数大于1的局面产生,也就是说在必败局面下,无论怎么合法操作都会转化为必胜局面。
综上四种局面,我们就证明了必胜局面可以转化为必败局面,必败局面必定转化为必胜局面。
问题:有两个绝顶聪明的人在玩取石子游戏,假设有n堆石子,每个人可以轮流在不超过k堆石子中拿走任意数量的石子(不能为0),无法拿石子的一方失败,问先手还是后手胜利。
还是延续之前尼姆博弈的基本思路,给出结论,证明结论。
当且仅当所有堆石子数在二进制下的各位上的1的数目都满足是k+1的倍数的时候是必败局面。
1.石子数为0的时候是必败局面且各位上的1的数目均为0,满足为k+1的倍数。
2.当各位上1的数目都是k+1的倍数且存在至少一位上1的数目不为0的时候,由于只能改变k堆的石子数,故同一位上最多增加或减少k个1,故任意合法操作都必将使得至少一位上的1的个数不为k+1的倍数,也就是必败局面必将转向必胜局面。
3.当存在一位上的1的数目不是k+1的倍数的时候,一定存在合法操作使得各位上的1的数目都是k+1的倍数。下面我们将构造出这种合法的操作。
假设我们现在考虑到第i位,而对于更高的位都已经满足1的个数是k+1倍数的条件,并且已经合法更改了m个堆的石子数的值,而在除去这m堆以外的剩余堆里面在第i位上有x个1,令r=x%(k+1)。易知对于这m堆在第i位上可以任意选择1和0的分布,于是分类讨论有两种情况。
(1).如果 r ≤ k − m \mathbf{r\le k-m} r≤k−m,我们可以将第m堆和r堆中的所有石子数的第i位置为0。
(2).如果 r > k − m \mathbf{r>k-m} r>k−m,我们可以在m堆中选择k+1-r 堆在第i位置为1,而其他堆在第i位置为0,由于 k + 1 − r < k + 1 − ( k − m ) < 1 + m ⇒ k + 1 − r ≤ m \mathbf{k+1-r
由于对于任意i都能找到合法的操作满足条件,故一定存在合法的操作使得必胜局面转化为必败局面。
综上所述,给出的结论是正确的。
问题:有两个绝顶聪明的人在玩取石子游戏,假设有n堆石子,每个人可以轮流在任意一堆石子中中拿走不超过k个石子(不能为0),无法拿石子的一方失败,问先手还是后手胜利。
结论:当且仅当所有堆石子数模k+1的异或和为0的时候为必败局面
证明方法基本同上。
前面谈到了三种Nim游戏,事实上这三种游戏都具有一个共性,用专业的术语来说它们都属于经典的公平组合游戏(ICG)。
关于ICG有如下定义(引自百度百科):
满足以下条件的游戏是ICG(可能不太严谨):
1、有两名选手;
2、两名选手交替对游戏进行移动(move),每次一步,选手可以在(一般而言)有限的合法移动集合中任选一种进行移动;
3、对于游戏的任何一种可能的局面,合法的移动集合只取决于这个局面本身,不取决于轮到哪名选手操作、以前的任何操作、骰子的点数或者其它什么因素;
4、如果轮到某名选手移动,且这个局面的合法的移动集合为空(也就是说此时无法进行移动),则这名选手负。根据这个定义,很多日常的游戏并非ICG。例如象棋就不满足条件3,因为红方只能移动红子,黑方只能移动黑子,合法的移动集合取决于轮到哪名选手操作。
对于所有的ICG都有一个统一的解决方案,我们先看一个模型:给定一个有向无环图和一个起始顶点上的一枚棋子,两名选手交替的将这枚棋子沿有向边进行移动,无法移动者判负。
如果我们把Nim游戏中的每一个石堆的石子数看作是一个状态,对应到一个棋子,合法操作(拿石子)看作是移动棋子,合法操作的多种可能的结果对应到有向图的一条边。那么游戏失败的标志就是所有的棋子都被移到一个出度为0的节点。
这样我们就合理化地从Nim游戏抽象出来了一个关于有向无环图的模型(无环是因为局面是不可逆的)。事实上不仅是Nim游戏,所有的ICG都可以抽象为这个模型。在这个模型中,棋子的移动互不关联,仅仅取决于棋子在有向图中的位置,完美的符合了ICG的定义。
为了更好地表示棋子在有向图上的移动,这里将正式给出SG函数的定义:
S G ( x ) = m e x { S G ( y ) ∣ y 是 x 的后继 } \mathbf{SG(x)=mex \{ SG(y) | y是x的后继\}} SG(x)=mex{SG(y)∣y是x的后继}( m e x { a 1 , a 2 . . . a n } 代表 { a 1 , a 2 . . . a n } 中没有出现的最小非负整数,特别地 m e x { } = 0 ) mex\{a_1,a_2...a_n\}代表\{a_1,a_2...a_n\}中没有出现的最小非负整数,特别地mex\{\}=0) mex{a1,a2...an}代表{a1,a2...an}中没有出现的最小非负整数,特别地mex{}=0)
在有向图的每一个节点上定义一个SG值,这样我们就可以通过SG值来表征每个点的状态。下面来思考这些SG值的意义,先考虑图上只有一个棋子的情况,如果棋子位于的点的出度为0,自然地SG值也是0,意味着这是一个必败局面。如果沿着边反向走,从终点出发走到的第一个点对应的SG值必然不为0,并且该点对应的也是一个必胜局面,因为存在一条边走向必败局面。根据这个逻辑,我们可以猜测SG为0的时候对应的局面是必败局面,否则是必胜局面。
证明也非常简单,就像前面证明Nim游戏一样,只要能够证明必胜局面能够走向必败局面,必败局面一定走向必胜局面即可。
证明:1.对于出度为0的点SG为0,且是必败局面,符合定义。
2.对于SG不为0的点,根据SG函数定义可知该点的后继存在一个点的SG为0,故必胜局面可以走向必败局面。
3.对于SG为0且出度不为0的点,根据SG函数的定义可知该点的后继不存在SG为0的点,即所有后继SG均大于0,故必败局面必走向必胜局面
由上面的证明可以知道的是在图只有一个棋子的情况下,通过SG是否为0就能够判定必胜局面和必败局面。对于多个棋子的情况,我们先给出结论:
设有n个棋子,每个棋子对应的SG值为 { S G 1 , S G 2 , S G 3 . . . S G n } \mathbf{\{SG_1,SG_2,SG_3...SG_n\}} {SG1,SG2,SG3...SGn},如果 S G 1 ⊕ S G 2 ⊕ S G 3 ⊕ . . . ⊕ S G n = 0 \mathbf{SG_1\oplus SG_2 \oplus SG_3 \oplus...\oplus SG_n=0} SG1⊕SG2⊕SG3⊕...⊕SGn=0则这是一个必败局面,否则是一个必胜局面。
证明也非常简单,参考前面关于尼姆博弈的证明,我们可以类似地给出如下证明。
证明:1.当所有点的出度为0的时候是一个必败局面,且满足 S G 1 ⊕ S G 2 ⊕ S G 3 ⊕ . . . ⊕ S G n = 0 \mathbf{SG_1\oplus SG_2 \oplus SG_3 \oplus...\oplus SG_n=0} SG1⊕SG2⊕SG3⊕...⊕SGn=0,符合定义。
2.当 S G 1 ⊕ S G 2 ⊕ S G 3 ⊕ . . . ⊕ S G n = 0 \mathbf{SG_1\oplus SG_2 \oplus SG_3 \oplus...\oplus SG_n= 0} SG1⊕SG2⊕SG3⊕...⊕SGn=0且存在节点出度不为0的的时候,由于任意走一个棋子都会改变相应地SG值,也将导致SG异或和不为0,故从必败局面出发必将走向必胜局面。
3.当 S G 1 ⊕ S G 2 ⊕ S G 3 ⊕ . . . ⊕ S G n ≠ 0 \mathbf{SG_1\oplus SG_2 \oplus SG_3 \oplus...\oplus SG_n\ne 0} SG1⊕SG2⊕SG3⊕...⊕SGn=0的时候,一定存在移动方案使得异或和为0。类比尼姆博弈的构造方法,设异或和为y,那么找到对y的最高位的1有贡献的 S G i \mathbf{SG_i} SGi,然后让该棋子走向SG值为 S G i ⊕ y ( S G i ⊕ y < S G i ) \mathbf{SG_i\oplus y(SG_i\oplus y
综上三点,我们成功证明了这个结论。
然后进一步地可以发现,由于棋子之间并不存在影响,证明过程也并不要求棋子到底位于哪张有向图上,也就是说可以让棋子位于不同的图上,然后每次移动都可以去选择让哪个棋子移动,这样整个游戏也变得更加灵活。
概括来说,对于任意多个不同规则的ICG,我们都可以将这些ICG的规则转化为若干有向图上的边,将游戏的操作转化为棋子的移动,将游戏的局面看做有向图上的若干个棋子的当前所在位置。然后通过计算每个棋子对应的SG值的异或和来确定当前局面是必胜局面或是必败局面。
计算SG函数的方法可以打表找规律,也可以数学推公式,还可以用结论。
下面先给出一些常见的游戏规则对应的SG函数,以取石子为例(对应有向图中点的标号与石子个数相同,因为点的标号的目的在于区分不同的状态,而石子个数显然能够区分不同的状态)。
1.可选择1~m颗石子, S G [ x ] = S G [ x ] % ( m + 1 ) \mathbf{SG[x]=SG[x]\%(m+1)} SG[x]=SG[x]%(m+1)。
2.可选步数为任意步, S G [ x ] = x \mathbf{SG[x]=x} SG[x]=x。
3.可选步数为规定的整数,用打表模板。
下面给出打表的模板:
#include
#define FOR(i,a,b) for(register int i=(a);i<(b);++i)
#define ROF(i,a,b) for(register int i=(a);i>=(b);--i)
#define pi pair<int,int>
#define mk(a,b) make_pair(a,b)
#define mygc(c) (c)=getchar()
#define mypc(c) putchar(c)
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef double db;
const int maxn = 10000;
const int maxm = 100;
const int inf = 2147483647;
typedef long long ll;
const double eps = 1e-9;
const long long INF = 9223372036854775807ll;
ll qpow(ll a,ll b,ll c){ll ans=1;while(b){if(b&1)ans=ans*a%c;a=a*a%c;b>>=1;}return ans;}
inline void rd(int *x){int k,m=0;*x=0;for(;;){mygc(k);if(k=='-'){m=1;break;}if('0'<=k&&k<='9'){*x=k-'0';break;}}for(;;){mygc(k);if(k<'0'||k>'9')break;*x=(*x)*10+k-'0';}if(m)(*x)=-(*x);}
inline void rd(ll *x){int k,m=0;*x=0;for(;;){mygc(k);if(k=='-'){m=1;break;}if('0'<=k&&k<='9'){*x=k-'0';break;}}for(;;){mygc(k);if(k<'0'||k>'9')break;*x=(*x)*10+k-'0';}if(m)(*x)=-(*x);}
inline void rd(db *x){scanf("%lf",x);}
inline int rd(char c[]){int i,s=0;for(;;){mygc(i);if(i!=' '&&i!='\n'&&i!='\r'&&i!='\t'&&i!=EOF) break;}c[s++]=i;for(;;){mygc(i);if(i==' '||i=='\n'||i=='\r'||i=='\t'||i==EOF) break;c[s++]=i;}c[s]='\0';return s;}
inline void rd(int a[],int n){FOR(i,0,n)rd(&a[i]);}
inline void rd(ll a[],int n){FOR(i,0,n)rd(&a[i]);}
template <class T, class S> inline void rd(T *x, S *y){rd(x);rd(y);}
template <class T, class S, class U> inline void rd(T *x, S *y, U *z){rd(x);rd(y);rd(z);}
template <class T, class S, class U, class V> inline void rd(T *x, S *y, U *z, V *w){rd(x);rd(y);rd(z);rd(w);}
inline void wr(int x){if(x < 10) putchar('0' + x); else wr(x / 10), wr(x % 10);}
inline void wr(int x, char c){int s=0,m=0;char f[10];if(x<0)m=1,x=-x;while(x)f[s++]=x%10,x/=10;if(!s)f[s++]=0;if(m)mypc('-');while(s--)mypc(f[s]+'0');mypc(c);}
inline void wr(ll x, char c){int s=0,m=0;char f[20];if(x<0)m=1,x=-x;while(x)f[s++]=x%10,x/=10;if(!s)f[s++]=0;if(m)mypc('-');while(s--)mypc(f[s]+'0');mypc(c);}
inline void wr(db x, char c){printf("%.15f",x);mypc(c);}
inline void wr(const char c[]){int i;for(i=0;c[i]!='\0';i++)mypc(c[i]);}
inline void wr(const char x[], char c){int i;for(i=0;x[i]!='\0';i++)mypc(x[i]);mypc(c);}
template<class T> inline void wrn(T x){wr(x,'\n');}
template<class T, class S> inline void wrn(T x, S y){wr(x,' ');wr(y,'\n');}
template<class T, class S, class U> inline void wrn(T x, S y, U z){wr(x,' ');wr(y,' ');wr(z,'\n');}
template<class T> inline void wra(T x[], int n){int i;if(!n){mypc('\n');return;}FOR(i,0,n-1)wr(x[i],' ');wr(x[n-1],'\n');}
vector<int>f;
int sg[maxn],vis[maxn];
void getSG(int n,int maxx){//打表sg[0],sg[1]...sg[n],maxx代表sg值的上限
sort(f.begin(),f.end());
memset(sg,0,sizeof(int)*(n+1));
FOR(i,1,n+1){
FOR(j,0,f.size()){
if(f[j]>i)break;
vis[sg[i-f[j]]]=1;
}
FOR(j,0,maxx+1)if(!vis[j]){
sg[i]=j;
break;
}
FOR(j,0,f.size()){
if(f[j]>i)break;
vis[sg[i-f[j]]]=0;
}
}
}
int main(){
//测试
f.push_back(1);
f.push_back(5);
getSG(100,50);
wra(sg,100);
}
通过将ICG抽象为有向图,在此理论基础上研究SG函数的规律,我们可以解决很多的ICG,下面将给出一些经典的题目来熟悉SG函数的运用,这些题目同时也是尼姆博弈的扩展版本。
问题一:有两个绝顶聪明的人在玩取石子游戏,假设有n堆石子,每个人可以轮流选择一堆中拿1~m颗石子,无法拿石子的一方失败,问先手还是后手胜利。
题解:先将问题抽象为有向图模型:每堆石子对应到一个棋子,n堆石子对应n个棋子,由于每个棋子的移动规则相同,所以n个棋子位于同一张有向图上,然后求出每个棋子的SG值即可。
根据前面得到的结论可知, S G [ x ] = S G [ x ] % ( m + 1 ) \mathbf{SG[x]=SG[x]\%(m+1)} SG[x]=SG[x]%(m+1),有n堆石子,所以只需要求出n个棋子的SG值的异或和即可,异或和为0则为必败局面,否则为必胜局面。
问题二:有两个绝顶聪明的人在玩取石子游戏,假设有n堆石子放在标号为1~n的台阶上,台阶高度按标号递增,0标号代表地面。现在每个人轮流取石子,每次可以从标号为i(i>0)的台阶上取任意数量(不能为0)的石子放在标号为i-1的台阶上,如果i为1就是放在地面上。如果没有石子可取就失败,问先手胜利还是后手胜利。
题解:这道题是经典的阶梯博弈,需要在传统Nim游戏上进行转换,注意到如果一方从偶数台阶上取石子放到奇数台阶上的时候,另一方可以立刻可以把这些石子放到下一个偶数台阶上,直到放到地面,如果这样操作的话,对于奇数台阶上的石子来说是没有变化的。考虑为何会产生这种操作,假设只考虑奇数台阶上的石子时是先手胜,那么先手只需要操作奇数台阶的石子即可,后手虽然也可以操作奇数台阶上的石子,但是由于奇数台阶是对先手来说是必胜局面,意味着总有一次轮到后手操作的时候后手不得不操作偶数台阶(因为奇数台阶上的石子都没有了),先手为了保证自己在奇数台阶上的优势一定会将后手刚从偶数台阶推向奇数台阶的石子又推向下一个偶数台阶,相当于奇数台阶上的局势没有发生变化,直到偶数台阶石子都消失的时候先手就胜利了。而当奇数台阶上的局面是必败局面的时候同理后手一定会类似地维护奇数台阶上的局面,一旦先手将偶数台阶上的石子推向奇数台阶时后手也一定会将其推向下一个偶数台阶直到地面,最终导致先手的失败。
综上,这道题经过转化后就只需要考虑奇数台阶上的局面即可,将奇数台阶上的石子推向偶数台阶的操作可以视为拿走奇数台阶上的石子,这就与传统的尼姆博弈没有任何区别了,套用SG函数的计算方法即可判定胜负。
问题:有两堆各若干个石子,两个人轮流从某一堆取至少一个或同时从两堆中取同样多的石子,规定每次至少取一个,多者不限,最后取光者得胜,问先手胜还是后手胜。
威佐夫博弈(Wythoff)也是一种ICG,不过它的SG值并不好求解,因此需要从另外的角度思考这种博弈的解决方案。
我们用二元组(a,b)表示两堆石子的数量,且a<=b,然后考虑必败局面的时候a与b的关系。
首先(0,0)是必败局面,接下来一个必败局面是(1,2),其次是(3,5),然后是(4,7),(6,10),(8,13)…设第i个必败局面为 ( a i , b i ) \mathbf{(a_i,b_i)} (ai,bi),i从0开始,根据规律可以猜测 a i = m e x { a 0 , b 0 , a 1 , b 1 . . . a i − 1 , b i − 1 } , b i = a i + i \mathbf{a_i=mex\{a_0,b_0,a_1,b_1...a_{i-1},b_{i-1}\},b_i=a_i+i} ai=mex{a0,b0,a1,b1...ai−1,bi−1},bi=ai+i。
下面证明这个规律是正确的。
1.(0,0) 是一个必败局面,符合定义。
2. ( a i , b i ) ( a i , b i 不为 0 ) \mathbf{(a_i,b_i)(a_i,b_i不为0)} (ai,bi)(ai,bi不为0)局面可以有三种转化方式,一是让 a i \mathbf{a_i} ai减少,二是让 b i \mathbf{b_i} bi减少,三是让 a i \mathbf{a_i} ai与 b i \mathbf{b_i} bi同时减少一个相同的值k(k>0)。
前两种转化方式的结果是类似地,以第一种为例,由于 a i = m e x { a 0 , b 0 , a 1 , b 1 . . . a i − 1 , b i − 1 } \mathbf{a_i=mex\{a_0,b_0,a_1,b_1...a_{i-1},b_{i-1}\}} ai=mex{a0,b0,a1,b1...ai−1,bi−1},所以 a i \mathbf{a_i} ai与前面所有的对偶的a与b的值都不相同,由于 b i = a i + i > b i − 1 = a i − 1 + i − 1 \mathbf{b_i=a_i+i>b_{i-1}=a_{i-1}+i-1} bi=ai+i>bi−1=ai−1+i−1,故 b i \mathbf{b_i} bi也一定与前面的所有对偶的a与b的值不相同,因此当 a i \mathbf{a_i} ai减少后得到的偶对也一定不可能与之前的偶对相同(之后的更不可能)。假设这个新的局面是 ( a i ′ , b i ) \mathbf{(a_i',b_i)} (ai′,bi),故 ( a i ′ , b i ) \mathbf{(a_i',b_i)} (ai′,bi)不是一个必败局面,也就是说它是一个必胜局面,也就是说通过前两种转化方式一定将必败局面转化为必胜局面。
对于第三种转化方式,由于 a i \mathbf{a_i} ai与 b i \mathbf{b_i} bi同时减少了一个值k,设这个新得到的局面为 ( a i ′ , b i ′ ) \mathbf{(a_i',b_i')} (ai′,bi′),这意味着它们的差值并不会变,仍然是i,而对于任意偶对 ( a j , b j ) ( j ≠ i ) \mathbf{(a_j,b_j)}(j\ne i) (aj,bj)(j=i)而言,它们的差值为 j ≠ i \mathbf{j\ne i} j=i,因此不存在偶对与 ( a i ′ , b i ′ ) \mathbf{(a_i',b_i')} (ai′,bi′)相同,也就意味着 ( a i ′ , b i ′ ) \mathbf{(a_i',b_i')} (ai′,bi′)并不是一个必败局面,即是一个必胜局面。这样再第三种转化下必败局面也会转化为必胜局面。
综上三种转化方式均会导致必败局面转化为必胜局面。
3.对于一个必胜局面 ( x , y ) ( x ≤ y ) \mathbf{(x,y)(x\le y)} (x,y)(x≤y)而言,满足它不是任意一个 ( a i , b i ) \mathbf{(a_i,b_i)} (ai,bi)对,首先 a i 与 b i \mathbf{a_i与b_i} ai与bi足够取到所有的非负整数(看这个偶对的定义即可理解),故x的值可以分为两种情况。
当 x = a i \mathbf{x=a_i} x=ai时,若 y > b i \mathbf{y>b_i} y>bi,那么从y的那堆取走 y − b i \mathbf{y-b_i} y−bi个石子即可;若 y < b i \mathbf{y
当 x = b i \mathbf{x=b_i} x=bi时,则 y ≥ x ≥ a i \mathbf{y\ge x\ge a_i} y≥x≥ai,因此只需要让y减去 y − a i \mathbf{y-a_i} y−ai即可,转化为 ( b i , a i ) \mathbf{(b_i,a_i)} (bi,ai)的偶对。
综上在所有情况下必胜局面都有一种合法操作转化为必败局面。
到此我们已经证明了必败局面当且仅当 ( a i , b i ) \mathbf{(a_i,b_i)} (ai,bi),其中 a i = m e x { a 0 , b 0 , a 1 , b 1 . . . a i − 1 , b i − 1 } , b i = a i + i \mathbf{a_i=mex\{a_0,b_0,a_1,b_1...a_{i-1},b_{i-1}\},b_i=a_i+i} ai=mex{a0,b0,a1,b1...ai−1,bi−1},bi=ai+i。
不过这还不够,如果要像这样递推下去的话复杂度显然太高了,数字一大就很难给出正解。因此解决本题还需要找到关于 a i \mathbf{a_i} ai和 b i \mathbf{b_i} bi的确切公式。解决这个问题需要用到一个引理:Beatty 定理(贝蒂定理)
定理描述如下:设集合 P = { p ∣ p = ⌊ n x ⌋ , n ∈ N + } , Q = { q ∣ q = ⌊ m y ⌋ , m ∈ N + } \mathbf{P=\{p|p=\lfloor nx\rfloor,n\in N^+ \},Q=\{q|q=\lfloor my\rfloor,m \in N^+\}} P={p∣p=⌊nx⌋,n∈N+},Q={q∣q=⌊my⌋,m∈N+},对于两个无理数x,y,若其满足 1 x + 1 y = 1 \mathbf{\frac 1x+\frac 1y=1} x1+y1=1,则 P ∩ Q = ∅ 且 P ∪ Q = N + \mathbf{P\cap Q=\empty且P\cup Q=N^+} P∩Q=∅且P∪Q=N+。
有了贝蒂定理之后就可以得到:
a i = ⌊ i ⋅ 5 + 1 2 ⌋ , b i = ⌊ i ⋅ 5 + 3 2 ⌋ \mathbf{a_i=\lfloor i\cdot \frac{\sqrt 5+1}{2}\rfloor,b_i=\lfloor i\cdot \frac{\sqrt 5+3}{2}\rfloor} ai=⌊i⋅25+1⌋,bi=⌊i⋅25+3⌋
容易验证 a i \mathbf{a_i} ai和 b i \mathbf{b_i} bi能够取遍所有非负整数,且满足 b i − a i = i \mathbf{b_i-a_i=i} bi−ai=i。
综上所述,对于 (x,y)(x<=y) 局面,只需要验证一下 x = ⌊ ( y − x ) ⋅ 5 + 1 2 ⌋ \mathbf{x=\lfloor (y-x)\cdot \frac{\sqrt 5+1}{2}\rfloor} x=⌊(y−x)⋅25+1⌋这个等式是否成立即可,成立的话就是必败局面,否则为必胜局面。
问题:有一堆个数为n(n>=2)的石子,有两个绝顶聪明的人轮流取石子,先手第一次取石子的时候不能取完,此后每个人取的石子数量都不能超过对方最近一次取石子数量的两倍,取完最后一颗石子的人胜利,问先手胜还是以后手胜。
这道题并不是一道ICG,因为双方的决策并不只受当前局面的影响,还受到对方决策的影响,因此这道题的解决办法还是得另辟蹊径。
先给出结论:当且仅当n为斐波拉契数列中的项的时候为必败局面。
设斐波拉契数列的第i项为 f i \mathbf{f_i} fi考虑用数学归纳法证明这个结论。
当n=2的时候,显然是必败局面。
假设当 n = f i ( i < = k ) \mathbf{n= f_i (i<=k)} n=fi(i<=k)的时候是必败局面,下面证明 n = f i + 1 \mathbf{n=f_{i+1}} n=fi+1的时候也是必败局面(注意到这不是ICG,因此不能套用前面胜利局面与失败局面的定义来证明本题)。此时满足 f i + 1 = f i + f i − 1 \mathbf{f_{i+1}=f_i+f_{i-1}} fi+1=fi+fi−1,由于 f i < = 2 ⋅ f i − 1 \mathbf{f_i<=2\cdot f_{i-1}} fi<=2⋅fi−1,先手必定不能拿多于或等于 f i − 1 \mathbf{f_{i-1}} fi−1个石子,此外,由于 n = f i − 1 \mathbf{n=f_{i-1}} n=fi−1是必败局面,故后手一定可以刚好拿走 f i − 1 \mathbf{f_{i-1}} fi−1中的最后一颗石子。由于后手最多可以拿先手所拿石子的两倍,故后手最多恰好拿走 2 3 f i − 1 \mathbf{\frac 23f_{i-1}} 32fi−1从而使得总石子数变为 f i \mathbf{f_{i}} fi,此时先手最多可以拿 4 3 f i − 1 \mathbf{\frac 43f_{i-1}} 34fi−1个石子,不过 4 3 f i − 1 − f i = 1 3 f i − 1 − f i − 2 < 0 \mathbf{\frac 43f_{i-1}-f_{i}=\frac 13f_{i-1}-f_{i-2}<0} 34fi−1−fi=31fi−1−fi−2<0故先手仍不可能拿完最后这 f i \mathbf{f_i} fi个石子,如果先手不能拿完的话,考虑到当初始局面 n = f i \mathbf{n=f_i} n=fi的时候先手必败,且是在先手任意拿石子(不能拿完)的前提下必败,此时则局限于 [ 1 , 4 3 f i − 1 ] \mathbf{[1,\frac 43f_{i-1}]} [1,34fi−1]的范围,则必败无疑,故无论如何抉择在 n = f i + 1 \mathbf{n=f_{i+1}} n=fi+1的局面下先手都会失败。
综上所述,当n为斐波拉契的项时一定是必败局面。
现在再考虑n不为斐波拉契的项时的局面。这时候需要用到Zeckendorf定理(齐肯多夫定理):任何正整数都可以表示为若干个不连续的斐波拉契数之和。
先说明如何将正整数拆分为斐波拉契数,先找到一个斐波拉契数 f i k \mathbf{f_{i_k}} fik使得 f i k < n < f i k + 1 \mathbf{f_{i_k}
考虑构造一种合法的操作使得先手胜利。先手第一步拿走 f i 1 \mathbf{f_{i_1}} fi1个石子,由于 2 ⋅ f i 1 < f i 2 \mathbf{2\cdot f_{i_1}
通过这种构造方法我们发现先手一定会胜利,因此n不为斐波拉契数的时候是必胜局面。
双人零和博弈中要求在任意局势下双方受益和为零。假设一方收益矩阵为 A A A,则满足另一方收益矩阵为 − A -A −A。现在考虑一方做出 i i i选择的概率为 p i p_i pi,那么要求 ∑ i p i A i , j ≥ v \sum_ip_iA_{i,j}\ge v ∑ipiAi,j≥v对于 j = 1 , j = 2 , . . . , j = n j=1,j=2,...,j=n j=1,j=2,...,j=n都满足。使得 v v v最大化。考虑令 x i = p i v x_i=\frac{p_i}{v} xi=vpi,满足 ∑ i x i = 1 v \sum_ix_i=\frac 1v ∑ixi=v1,我们的目标是最小化 ∑ i x i \sum_i x_i ∑ixi,同时要满足 n n n个约束即可。这可以用线性规划求解。
问题:给定n堆石子,双方轮流每次可以选择i,j,k三堆石子(i
首先可以发现每个石子是独立的,你可以认为每个石子都是一个单独的ICG游戏,它的sg值只取决于它的位置,因此定义sg函数为 S G ( i ) SG(i) SG(i)其中 i i i代表位置 i i i,显然 i i i位置的一颗石子对应的后继是 j , k j,k j,k处的两颗石子,所以 S G ( x ) = m e x i < j < = k < = n { S G ( j ) x o r S G ( k ) } SG(x)=mex_{i
问题:给定n个硬币从左到右放一排,有的硬币正面朝上,有的反面朝上,两个人轮流操作,每次操作可以选择一个正面朝上的硬币翻转,同时还可以选择一个该硬币左边的硬币翻转(也可以不选择),不能操作的人失败,问谁必胜。
结论是这个游戏和nim游戏的 S G SG SG函数是一样的,第 i i i个硬币看成石子数为 i i i的一堆石子,整个游戏的 S G SG SG值就是所有石子的 S G SG SG值的异或和。
考虑如何证明。如果只有 1 1 1个硬币正面朝上,我们可以把这个硬币直接变成反面朝上,也可以把它反转后让它左边的某个硬币反面朝上,相当于把这枚硬币向左移动一段位置,容易联想到这个状态变化与nim游戏中一堆石子的数量变化是一致的,即对于位置 i i i的硬币,其 S G ( i ) = i SG(i)=i SG(i)=i。如果有多个硬币正面朝上的话,我们考虑整个游戏的 S G SG SG值,有两种求解方式,第一种是考虑把游戏拆分成多个子游戏,分别求出每个子游戏的 S G SG SG值后再全部异或起来;第二种是直接暴力枚举游戏的所有状态及其后继,通过 S G SG SG函数定义来递推求出每个状态的 S G SG SG值。我们尝试着把翻转硬币这个游戏和nim游戏在第二种方式上建立联系,首先我们随便选择一个编号为 i i i的硬币,这个操作我们映射为选择了石子数为 i i i的那堆石子(注意一开始每堆石子数量都不同),如果我们选择直接翻转这枚硬币,那么相当于直接把这堆石子都拿掉;如果我们选择左边一枚编号为 j j j的反面朝上的硬币反转,相当于让 i i i号硬币向左移动一段位置,等价于让这堆石子数量从 i i i变成 j j j。现在我们发现在这两种状态变化下,翻转硬币游戏和nim游戏的状态变化是一一对应的,那在让我们考虑最后一种状态变化:选择 i i i左边一枚编号为 k k k的正面朝上的硬币反转。第三种变化等价于把这堆石子数量变成 k k k,也就是和另一堆石子数也为 k k k的石子堆相同,注意到这两堆石子的 S G SG SG异或和为0,对整个游戏的 S G SG SG值没有贡献,也就是说这个状态等价于两堆石子都不存在的状态,反映到翻转硬币这个游戏中就等价于 i i i和 k k k号硬币都处于反面向上的状态,所到此为止我们成功建立了这两个游戏的状态转化关系,这些状态转化对 S G SG SG的影响是一模一样的,因此我们可以直接把翻转硬币等价于nim游戏,套用nim游戏的 S G SG SG公式计算即可。
(POI2003/2004 stage I Game)问题:给定长度为n的一行格子,某些格子上放着硬币,有些是空的,你每次选择一个硬币,放到离它最近的右边的空的格子上,如果右边没有空的格子就直接扔掉。两方轮流操作,不能操作就失败,问谁胜。
这道题如果去研究状态会觉得很复杂,根本无从下手,但是如果把两个空格子之间的硬币都看成放在一个阶梯上,这样你会发现其实这就是一道阶梯博弈!
(IPSC 2003 Got Root?)问题:给定一张无向连通图和节点u,每次操作选择一条边删除,然后将那些与节点u不连通的边和点删除。两个玩家轮流操作,不能操作的玩家输掉,问谁获胜。
这道题的解法来自IPSC 2003 Solution to Problem G – Got Root?,以下文字是对该英文题解的归纳总结。更具体的证明见论文《Winning Ways for Your Mathematical Plays》第一卷第7章
首先给出做法:对于一颗树而言,我们可以递归求解这颗树的 S G SG SG函数,如果这颗树根节点是 u u u,那么 S G ( u ) = x o r e d g e ( u , v ) { S G ( v ) + 1 } SG(u)=xor_{edge(u,v)}\{SG(v)+1\} SG(u)=xoredge(u,v){SG(v)+1}。如果是无向图的话,可以证明任何环上的点都可以缩成一个点加环的边数量的自环,这个自环还等价于从该缩点延伸出去的一条额外的边,这样我们可以将所有的边双连通分量都缩成一个点,把所有的自环等价变换为从缩点延伸出去的边,得到的是一颗树,然后按照树的 S G SG SG求解方法来做即可。
证明分为两个步骤。第一步先证明树上的 S G SG SG函数的求解方法的正确性,对于根节点 u u u而言,考虑其一个儿子 v v v及以它为根的子树,我们可以把 v v v和以它为根的子树等价转化为一条长度为 S G ( v ) SG(v) SG(v)的链,在这种转化下我们可以证明 S G ( u ) SG(u) SG(u)不会发生改变。考虑原图对应的游戏是 G G G,在做出这种等价转化后的游戏是 G ′ G' G′,现在考虑 G + G ′ G+G' G+G′这样一个游戏,如果先手必败,那么我们就可以得出 S G ( G ) = S G ( G ′ ) SG(G)=SG(G') SG(G)=SG(G′),方便起见我们只考虑 u u u只有一个儿子 v v v(这样考虑是没问题的,因为 u u u的儿子是相互独立的),在图 G ′ G' G′相应地有 u ′ u' u′和 v ′ v' v′,不过 v ′ v' v′的子树是一条长度为 S G ( v ) SG(v) SG(v)的链。先手一定不能选择 ( u , v ) (u,v) (u,v)或 ( u ′ , v ′ ) (u',v') (u′,v′),一旦选择其中一条边,那么后手就会断开另一条边,这样先手就输了。那么先手就会在 v ′ v' v′为根的子树和 v v v为根的子树上博弈,注意这是两个 S G SG SG相同的子游戏,意味着这两个子游戏的 S G SG SG值为0,因此先手不会拿掉 v v v为根的子树和 v ′ v' v′为根的子树中最后一条边,一旦 v v v为根的子树和 v ′ v' v′为根的子树被清空,那么先手必定要去选择删 ( u , v ) (u,v) (u,v)或 ( u ′ , v ′ ) (u',v') (u′,v′)边,意味着先手还是会输掉博弈,因此证得 S G ( G ) = S G ( G ′ ) SG(G)=SG(G') SG(G)=SG(G′)。于是我们可以把 v v v为根的子树直接等价转化为长度为 S G ( v ) SG(v) SG(v)的一条链,现在 v v v和 u u u多了一条连边,链条长度变成了 S G ( v ) + 1 SG(v)+1 SG(v)+1,一条链的异或函数就是它的长度本身,这就说明了 S G ( u ) = x o r e d g e ( u , v ) { S G ( v ) + 1 } SG(u)=xor_{edge(u,v)}\{SG(v)+1\} SG(u)=xoredge(u,v){SG(v)+1}。
第二步是最艰难的部分,我们需要证明无向图上的任何一个环都可以缩成一个点,环上的所有边对应缩成该缩点上的相同数量的自环。注意自环其实等价于从点连出去的一条额外边。
考虑边数最少,在边数同样少的情况下点数最少的这样一个反例 G G G,也就是说在这个反例中,如果把环缩成一个点会导致 S G SG SG值发生改变。那么这样一个反例具有如下特征:
这样我们对于这个反例的图像有了清晰的认识,大致如下图所示:
注意那些长长的枝条,它们利用了等价转化,把树转化为一个链条。
现在图 G G G已经是最简的形式了,我们考虑图 G ′ G' G′为图 G G G缩点后的情形,除了上图的链条链接到 u ′ u' u′点外,环上的边都变成连接 u ′ u' u′的边长为1的边。现在我们考虑在 G + G ′ G+G' G+G′上博弈,我们只要证明先手必败,就表明最小的反例不存在,整个证明也得已结束。
先手可以选择链条中的一条边删除,如果这样的话,后手也选择对称的图中的对应的链条的边删除,这样由于图 G G G少了一条边,不是最小的反例了,所以可以做等价转换,图 G G G和图 G ′ G' G′的 S G SG SG值也就保证相等了,这样就是必败了,所以先手一定不能选择链条中的一条边删除。
再考虑先手选择图 G G G中环上的一条边删除,如果这样的话,图 G G G就变成了一棵树, G ′ G' G′也是一颗树,我们面对的游戏是一颗森林!于是考虑套用 S G SG SG计算公式,不过我们把异或改成加法,并且只考虑最后一位的变化,可以发现异或奇偶性与加法奇偶性相同,意味着边数的奇偶性代表了 S G SG SG值的奇数偶性,显然先手只删除了一条边,图 G + G ′ G+G' G+G′中应该只存在奇数条边,因此 S G SG SG为奇数,大于0,意味着此时处于必胜态,也就是说先手必败,因此先手一开始也不能删除图 G G G中的环上的一条边。
现在还有最后一种情况,先手可以选择图 G ′ G' G′中的一条额外边删除,此时我们分三种情况考察一下后手是否必胜:
至此我们证明了环上的点一定可以被缩成一个点加一些自环(或额外的边长为1的边)。
博弈论的知识点不是特别多,但是有些套路不去理解在赛场上就做不出来,因此本文主要是梳理一下关于博弈的基础知识,一遍作者日后复习,也给广大对博弈论感到困惑的读者提供帮助。没有给出练习题,以后有空的话可能还会完善本篇博文。
参考资料及博客:
[1].https://blog.csdn.net/clover_hxy/article/details/53818624
[2].https://www.cnblogs.com/lfri/p/10662291.html
[3].https://www.cnblogs.com/nanjoqin/p/10211576.html
[4].https://www.luogu.com.cn/problem/solution/P2197
[5].https://baike.baidu.com/item/Nim%E6%B8%B8%E6%88%8F/6737105?fr=aladdin
[6].https://baike.baidu.com/item/SG%E5%87%BD%E6%95%B0/1004609?fr=aladdin
[7].https://www.luogu.com.cn/problem/solution/P2252
[8].https://baike.baidu.com/item/%E8%B4%9D%E8%92%82%E5%AE%9A%E7%90%86/2677437?fr=aladdin
[9].https://blog.csdn.net/dgq8211/article/details/7602807
[10].https://baike.baidu.com/item/%E9%BD%90%E8%82%AF%E5%A4%9A%E5%A4%AB%E5%AE%9A%E7%90%86/7612155?fr=aladdin
[11].https://blog.csdn.net/tinyDolphin/article/details/75500903?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param