转载请注明出处http://write.blog.csdn.net/postlist
___取石子游戏
一、什么是无偏博弈?
无偏博弈就是一种任意局势对参与游戏的两个选手来说都是平等的回合制游戏。因此,选手的区别只在于谁先进行第一个回合(即谁是先手)。按此定义,象棋、五子棋等都不是无偏博弈。这是因为,在这些棋类中,对于任意一个局势,有些棋子只能由某一选手移动;例如,在中国象棋中执红的选手在每一回合中只能操作红棋,而不能操作黑棋。
除了局势对选手平等之外,还有额外的三个要求:
(1)信息完全公开。这就是说,有关游戏的所有信息对所有选手都是可知的。因此,像扑克之类的游戏,通常都不是无偏博弈,因为,你看不到对手的牌,对手的也看不到你的。
(2)无随机性。一旦游戏完全设立好,每一人操作都是非随机的。这就排除了大富翁之类的游戏。
(3)有限步终止。游戏在有限步之内必然终止。这是一条很强的要求。例如,象棋之类的游戏就不满足这条要求。比如,当对手下感情棋时,游戏就可能无限进行下去。
尼姆(Nim)博弈
有两堆石子,石子数目为 m > 0 和 n > 0。两个选手轮流从这些石堆中取走石子。在每一回合中,选手选定一个至少有一个石子的石堆,从该堆中取走至少一个石子。若某选手最后取走所有的石子,则该选手获胜,游戏宣告结束。
有向无环图游戏
现在,设想一个有向无环图上(如无特别说明,本系列中的图都是指有向无环图)的棋子移动游戏:在一个有向无环图上,在某个顶点处有一颗棋子。在每一回合中,选手把该棋子沿某一出边移动到相邻的顶点上。当某选手最后移动棋子,从而使棋子处于一个没有出边的顶点上时,该选手获胜,游戏结束。
在无偏游戏中,把每一个局势,也即每一个状态,看成是一个有向图上的一个顶点,而把状态间的转移看成一条有向边。由于有限步原则,该图必然是无环图。在图上的对应于游戏最初状态的顶点处放置一颗棋子,采取某个策略把一个状态 x 变成状态 y则相当于把棋子从对应于状态 x 的顶点 u 沿着有向边移动到对应于状态 y 的顶点 v 上。当棋子无法移动时,游戏就结束
没有出边的顶点称为 P-态。如果一个状态可以转移到某一个 P-态,则称其为 N-态。如果一个状态只能转移到 N-态的顶点上,则也称为 P-态。在某回合中,如果选手面对的是 P-态,则当对手以最优策略进行游戏时,该选手必败。这是因为,如果该状态没有出边,则游戏结束,选手输掉了游戏;否则,无论他的策略是什么,都只能转移到某个N-态上,从而对手可以接着把该棋子转移到某个 P-态上。因此,P-态也叫必败态(相对于先手而言),N-态为必胜态(同样的,相对于先手而言)。一个很自然的问题是,对于任意一个顶点,是否要么为 P-态,要么为 N-态
三、Nim 和
(1)x⊕y=0 当且仅当 x=y
(2)x⊕0=x。
有一道有关异或运算的很有名的题目:给定一个数组,除了某个数只出奇数次之后,其它的数都出现了偶数次,请找出这个数。答案就是对所有数进行异或运算,结果就是所求的数。这正是因为 x⊕x=0,x⊕0=x。
四、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
在取石子游戏中,假定只有一堆石子,石子数目为 n。则 F(k)=k,0<=k<=n。特别的 F(n)=n。简单的思考可以证明,状态为 P-态当且仅当其 SG 值为0,为 N-态当且仅当 SG 值大于0。
Sprague-Grundy函数满足两个重要性质:
1 点v是一个P-状态当且仅当g(v)=0
2 如果G = G1 + G2 且 v = v1v2 是G的一个状态,那么g(v) 为g(v1) 和 g(v2) 在二进制下的异或: g(v) = g(v1) ⊕ g(v2).
我们的策略如下:如果轮到我们且游戏的Grundy值给出了一个非0的nim和,那么必然在游戏的某个组分中存在一个操作使得nim和变为0。我们应该执行这个操作,那么接着我们的对手就被迫再次使得nim和非0。最终,我们将成为在最后一个游戏执行最后一个操作的人,最后将nim和变为0
令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;
1 //这是网上一个很好看的求SG值的办法
2 int DFS(int n) /* 典型求 SG 函数的办法 */
3 {
4 int i;
5 if(SG[n]!=-1) return SG[n];
6 bool used[1010];
7 memset(used,0,sizeof(used));
8 for(i=0;i<N;i++)
9 {
10 if(map[n][i] != -1)
11 used[DFS(i)]=true;
12 }
13 i=0;
14 while(used[i]) i++;
15 return SG[n]=i;
16 }