博弈论

http://www.360doc.com/content/16/0313/12/21207324_541805330.shtml

通常的Nim游戏的定义是这样的:有若干堆石子,每堆石子的数量都是有限的,合法的移动是“选择一堆石子并拿走若干颗(不能不拿)”,如果轮到某个人时所有的石子堆都已经被拿空了,则判负(因为他此刻没有任何合法的移动)。

定义必败态和必胜态,
1.无法进行任何移动的局面是必败态;2.可以移动到必败态的局面是必胜态;3.所有移动都导致必胜态的局面是必败态。 按照这个定义,必败态和必胜态可以通过定义计算出来。

根据上面这个过程,可以得到一个递归的算法——对于当前的局面,递归计算它的所有子局面的性质,如果存在某个子局面是必败态,那么向这个子局面的移动就是必胜策略。

对于一个Nim游戏的局面(a1,a2,...,an),它是必败态当且仅当a1^a2^...^an=0,其中^表示异或(xor)运算。

这个定理的证明却也不复杂,基本上就是按照两种局面的证明来的。 根据定义,证明一种判断局面的性质的方法的正确性,只需证明三个命题:
1、这个判断将所有无法进行任何移动的局面判为必败态;
2、根据这个判断被判为必胜态的局面一定可以移动到某个必败态;
3、根据这个判断被判为必败态的局面无法移动到某个必败态。 
这三个命题显然成立。
根据这个定理,我们可以在O(n)的时间内判断一个Nim的局面的性质,且如果它是必胜态,也可以在O(n)的时间内找到所有的必胜策略。Nim问题就这样基本上完美的解决了。

现在我们来研究一个看上去似乎更为一般的游戏:给定一个有向无环图和一个起始顶点上的一枚棋子,两名选手交替的将这枚棋子沿有向边进行移动,无法移动者判负。事实上,这个游戏可以认为是所有博弈论问题的抽象模型。也就是说,任何一个博弈论问题都可以通过把每个局面看成一个顶点,对每个局面和它的子局面连一条有向边来抽象成这个“有向图游戏”。
下面我们就在有向无环图的顶点上定义sg(Sprague-Garundy)函数
首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。 对于一个给定的有向无环图,定义关于图的每个顶点的Sprague-Garundy函数g如下:sg(x)=mex{sg(y) | y是x的后继 }。 
来看一下SG函数的性质。
首先,所有的terminal position所对应的顶点,也就是没有出边的顶点,其SG值为0,因为它的后继集合是空集。然后对于一个g(x)=0的顶点x,它的所有后继y都满足 sg(y)!=0。对于一个sg(x)!=0的顶点,必定存在一个后继y满足sg(y)=0。 以上这三句话表明,顶点x所代表的局面是必败态当且仅当sg(x)=0。我们通过计算有向无环图的每个顶点的SG值,就可以对每种局面找到必胜策略了。

但SG函数的用途远没有这样简单。如果将有向图游戏变复杂一点,比如说,有向图上并不是只有一枚棋子,而是有n枚棋子,每次可以任选一颗进行移动,这时,怎样找到必胜策略呢? 
让我们再来考虑一下顶点的SG值的意义。当sg(x)=k时,表明对于任意一个0<=i<k,都存在x的一个后继y满足sg(y)=i。也就是说,当某枚棋子的SG值是k时,我们可以把它变成0、变成1、……、变成k-1,但绝对不能保持k不变。
联想到Nim游戏,Nim 游戏的规则就是:每次选择一堆数量为k的石子,可以把它变成0、变成1、……、变成k-1,但绝对不能保持k不变。这表明,如果将n枚棋子所在的顶点的 SG值看作n堆相应数量的石子,那么这个Nim游戏的每个必胜策略都对应于原来这n枚棋子的必胜策略! 对于n个棋子,设它们对应的顶点的SG值分别为(a1,a2,...,an),再设局面(a1,a2,...,an)时的Nim游戏的一种必胜策略是把 ai变成k,那么原游戏的一种必胜策略就是把第i枚棋子移动到一个SG值为k的顶点。这听上去有点过于神奇——怎么绕了一圈又回到Nim游戏上了。

刚才,认为n枚棋子是在一个有向图上移动。但如果不是在一个有向图上,而是每个棋子在一个有向图上,每次可以任选一个棋子(也就是任选一个有向图)进行移动,这样也不会给结论带来任何变化。 所以我们可以定义有向图游戏的和:设G1、G2、……、Gn是n个有向图游戏,定义游戏G是G1、G2、……、Gn的和(Sum),游戏G的移动规则是:任选一个子游戏Gi 并移动上面的棋子。Sprague-Grundy Theorem就是:sg(G)=sg(G1)^sg(G2)^...^sg(Gn)。也就是说,游戏的和的SG函数值是它的所有子游戏的SG函数值的异或。

有n堆石子,每次可以从第1堆石子里取1颗、2颗或3颗,可以从第2堆石子里取奇数颗,可以从第3堆及以后石子里取任意颗……我们可以把它看作3个子游戏,第1个子游戏只有一堆石子,每次可以取1、2、3颗,很容易看出x颗石子的局面的SG值是x%4。第2个子游戏也是只有一堆石子,每次可以取奇数颗,经过简单的画图可以知道这个游戏有x颗石子时的SG值是x%2。第3个游戏有n-2堆石子,就是一个Nim游戏。对于原游戏的每个局面,把三个子游戏的SG值异或一下就得到了整个游戏的SG值,然后就可以根据这个SG值判断是否有必胜策略以及做出决策了。
所以,SG函数与“游戏的和”的概念是把遇到的看上去有些复杂的游戏试图分成若干个子游戏,对于每个比原游戏简化很多的子游戏找出它的SG函数,然后全部异或起来就得到了原游戏的SG函数,就可以解决原游戏了。

 

sg函数:必败态的sg函数值为0,其它点的sg函数值为后继状态中没有出现的值的最小值

例如:有一个点的后继状态的sg分别是0,1,3,4。则该点的sg函数值为2

求sg函数值:gra表示图的邻接链表储存,subSeq表示该点的后继状态的函数值是否出现过

int sg[MAXN];  
vector<int> gra[MAXN];
  
int dfs(int a) {  
    if(sg[a] >= 0) return sg[a];  
    bool subSeq[MAXN] ;memset(subSeq,0,sizeof(subSeq));  
    for(int j = 0; j < gra[a].size(); ++j) {  
            sg[gra[a][j]] = dfs(gra[a][j]); 
            subSeq[sg[gra[a][j]]] = 1; 
    }  
    for(int i = 0; ; ++i) {  
        if(!subSeq[i]) {  
            return sg[a] = i; 
        }  
    }  
 };  
原文地址:https://www.cnblogs.com/lher/p/7149713.html