您的位置:首页 > 其它

初亏博弈门道

2015-08-25 13:13 190 查看
The Sprague-Grundy theory of impartial games

公平游戏的Sprague-Grundy定理

公平游戏是一种双人游戏,在游戏中双方都有完整的信息,没有牵涉,任何状态的合法操作对双方来说都是相同的。

一个公平游戏可以抽象地用一个有向无环图来表示,这个图中每个点都对应这一个状态,每条有向边代表从一个状态到另一个状态的合法操作。

我们可以想象一个代币最初放在某个点上,然后两个玩家轮流将其从当前的点移动到它的后继点。当代币移动到汇点时游戏结束,汇点是一个没有出度的点,最后一个需要操作的玩家就是胜者。

P- 和 N-状态

如果双方都按照最佳策略进行游戏,我们可以将游戏中的每个状态依据其是先手必胜还是后手必胜分类。

一个先手胜状态被认为是一个N-状态(因为下一个玩家即将获胜),一个后手胜状态被认为是一个P-状态(因为前一个玩家即将获胜)

P-和N-状态归纳性地描述如下:

一个点v是P-状态当且仅当它的所有后继都为N-状态

一个点v是N-状态当且仅当它的一些后继是P-状态

这个归纳从汇点开始,汇点是P-状态因为它显然满足P-状态的要求。

游戏的P-和N-状态的信息提供了它的必胜策略。如果轮到我们且游戏处在一个N-状态,我们应该转移到一个P-状态。接着我们的对手就会被迫进入N-状态,依此类推。我们最终会移入一个汇点并获得胜利。

游戏的和

如果G1和G2 是公平游戏,那么他们的和G1 + G2是另一个公平游戏,玩法如下:每个回合,一个玩家选择G1, G2 中的一个(随便哪个他希望的)然后玩它,不碰另一个游戏。当 G1 和 G2都不能操作时游戏结束。

形式上,如果 G1 = (V1, E1) 和 G2 = (V2, E2)是游戏图,那么他们的和 Gsum = (Vsum, Esum) 规定为:

Vsum = V1 × V2,

Esum = {(v1v2, w1v2) | (v1, w1) ∈ E1} ∪ {(v1v2, v1w2) | (v2, w2) ∈ E2}.

现在,假定我们给出两个游戏G1 和 G2。如果我们只知道单个游戏的P-状态和N-状态我们能够正确地玩好游戏和G1 + G2吗?答案是否定的。不难看出两个P-状态的和总是P-状态,P-状态和N-状态的和总是N-状态。但是两个N-状态的和既可能是P-状态也可能是N-状态。因此,只知道单个游戏的P-状态和N-状态是不够的。

为了正确地玩好游戏和我们需要推广P-状态和N-状态,它就是Sprague-Grudy函数(或者简称为Grundy函数)。

The Sprague-Grundy function

Sprague-Grundy 函数

令N = {0, 1, 2, 3, …} 为自然数的集合。Sprague-Grundy 函数给游戏中的每个状态分配了一个自然数。结点v的Grundy值等于没有在v的后继的Grundy值中出现的最小自然数。

形式上:给定一个有限子集 S ⊂ N,令mex S(最小排斥值)为没有出现在S中的最小自然数

mex S = min (N S).

现在,给定一个游戏图G=(V,E),其Sprague-Grundy函数g:V → N 归纳定义为

g(v) = mex {g(w) | (v, w) ∈ E}.

从G的汇点开始归纳,可知它的Grundy值为0

Sprague-Grundy函数满足两个重要性质:

点v是一个P-状态当且仅当g(v)=0

如果G = G1 + G2 且 v = v1v2 是G的一个状态,那么g(v) 为g(v1) 和 g(v2) 在二进制下的异或:

g(v) = g(v1) ⊕ g(v2).

运算⊕也称作nim和。举个例子,3 ⊕ 5 = 011 ⊕ 101 = 110 = 6。类似地,3 ⊕ 6 = 5 且 5 ⊕ 6 = 3。

不难利用归纳法证明上面两个性质。

根据这些性质有v = v1v2 是P-状态当且仅当g(v1) = g(v2), 因为这是唯一能够使得nim和为0的途径。

无疑,游戏的求和是满足交换律和结合律的运算,nim和运算也是。

因此,我们可以通过获知单个游戏的Grundy函数来正确地玩好任意数目游戏和。

我们的策略如下:如果轮到我们且游戏的Grundy值给出了一个非0的nim和,那么必然在游戏的某个组分中存在一个操作使得nim和变为0。我们应该执行这个操作,那么接着我们的对手就被迫再次使得nim和非0。最终,我们将成为在最后一个游戏执行最后一个操作的人,最后将nim和变为0.

The game of Nim

Nim游戏

最基本的公平游戏是Nim堆。一个Nim堆由确定数目代币组成。在每个回合,一个玩家从堆上拿走1到整堆中任意数目的代币。拿空整堆的人获得胜利。

这个游戏如果独立看是没有意义的:先手玩家可直接拿走所有代币并立即获得胜利!

但是如果我们将各种大小的Nim堆加在一起,我们就得到了著名的Nim游戏。

大小为n的Nim堆的Grundy值为n。因此,Nim游戏中每个状态的Grundy值为每堆大小的Nim和。

Games that decompose into sums of themselves

一些分解成自身和的游戏

Sprague-Grundy定理最自然的应用就是一些分解成自身和的一些游戏。

考虑下面这个游戏:有一个大小为m*n的棋盘,且有无限数目某特定形状的骨牌供应。在每个回合,玩家在棋盘上一个空位放置一个骨牌,不能放骨牌的玩家就是败者。

在游戏期间,棋盘会逐渐分成不同的区域,对其我们可以分别计算Grundy值。

再举个例子,考虑Grundy游戏。这个游戏的一个状态由一些不同大小的代币堆组成,一次操作由只取一堆并把它分成两个不相等的堆组成。当所有堆的大小只有1和2的时候游戏结束,因为它不能再分。

令g(n)为单个大小为n的堆的Grundy值。数列g(n)如下:

n: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20…

g(n):0 0 1 0 2 1 0 2 1 0 2 1 3 2 1 3 2 4 3 0

比如:

当n等于1,2时已满足条件,即不能再取,也就没有下一个局面,所以g(1)={};所以G(1)={0,1,2,3,4…};

所以g(1)=0;同理g(2)=0;依次递推,g(3),g(4),g(5)等,

例如:g(6)={#(1,5),#(2,4)}={g(1)+g(5),g(2)+g(4)}=g(2,0);

所以G(6)={1,3,4,5,6…},所以g(6)=1;

甲乙两人面对若干排石子,其中每一排石子的数目可以任意确定。例如图所示的初始局面:共n=3排,其中第一排的石子数a1=7,第二排石子数a2=3,第三排石子数a3=3。两人轮流按下列规则取走一些石子,游戏的规则如下:每一步必须从某一排中取走两枚石子;这两枚石子必须是紧紧挨着的;如果谁无法按规则取子,谁就是输家。

解:

用符号#S,表示局面S所对应的二进制数。

用符号$(x),表示局面(x)的下一步所有可能出现的局面的集合。

定义集合g(x):设$(x)={S1, S2, …, Sk},则g(x)={#S1, #S2, …, #Sk}。

函数f满足要求的一个充分条件

f(a1)不属于集合g(a1)。

集合g(a1)包含集合{0, 1, …, f(a1)–1}。

如果g(a1)={0, 1, 2, 5, 7, 8, 9},则f(a1)=3,满足要求。

用大写字母N表示非负整数集,即N={0, 1, 2, …}。

令N为全集,集合G(x)表示集合g(x)的补集。

定义函数f(n):f(n)=min{G(n)},即f(n)等于集合G(n)中的最小数。

设局面S=(a1, a2, …, an),#S=f(a1)+f(a2)+…+f(an),采用二进制数的加法。

若#S=0,则S负;若#S≠0,则S胜。

游戏C的f值:

g(0)={},G(0)={0, 1, …},f(0)=0;

g(1)={},G(1)={0, 1, …},f(1)=0;

g(2)={#(0)}={f(0)}={0},G(2)={1, 2, …},f(2)=1;

g(3)={#(1)}={f(1)}={0},G(2)={1, 2, …},f(3)=1;

g(4)={#(2), #(1, 1)}={f(2), f(1)+f(1)}={1, 0},G(4)={2, 3, …},f(4)=2;

g(5)={#(3), #(1, 2)}={f(3), f(1)+f(2)}={1, 1},G(5)={0, 2, 3, …},f(5)=0;

g(6)={#(4), #(1, 3), #(2, 2)}={2, 1, 0},G(6)={3, 4, …},f(6)=3;

g(7)={#(5), #(1, 4), #(2, 3)}={0, 2},G(7)={1, 3, 4, …},f(7)=1;

图2所示的局面S=(7, 3, 3),有#S=f(7)+f(3)+f(3)=1+1+1=1,故S胜。

游戏C的初始局面S=(3, 4, 6),有#S=1+2+3=01+10+11=0,故S负。

此类搏弈游戏的一般性解法:

用一个n元组(a1, a2, …, an),来描述游戏过程中的一个局面。

用符号#S,表示局面S所对应的二进制数。

用符号$(x),表示局面(x)的下一步所有可能出现的局面的集合。

定义集合g(x):设$(x)={S1, S2, …, Sk},则g(x)={#S1, #S2, …, #Sk}。  

令非负整数集为全集,集合G(x)表示集合g(x)的补集。

定义函数f(n):f(n)=min{G(n)},即f(n)等于集合G(n)中的最小数。

设局面S=(a1, a2, …, an),#S=f(a1)+f(a2)+…+f(an),采用二进制数的加法。

若#S≠0,则先行者有必胜策略;若#S=0,则后行者有必胜策略。

实现的一个代码如下:

int cmp(const void *a,const void *b)

{

return (int )a-(int )b;

}

int f[1000]={0,0,1,1};//初始化前4个

int g[500],c[1000];

int main()

{

int i,j,k,m,n,s;

for(i=4;i<=1000;i++)

{

m=0;

for(j=1;j<=i/2;j++)

{

g[m++]=f[j-1]^f[i-j-1];

}

qsort(g,m,sizeof(g[0]),cmp);//排序

for(k=0;;k++)

if(g[k]!=k)//找其补集的最小值

{

f[i]=k;//找到f[i]

break;

}

//printf(“a[%d]=%d\n”,i,a[i]);

}

while(scanf(“%d”,&n)!=EOF&&n)

{

for(i=0;i
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: