首页 > 代码库 > 小结 - 基础博弈
小结 - 基础博弈
小结一下基础博弈,因为暂时对博弈的理解还不是很深,只能说一下我对这段时间对博弈的认识。
博弈论的简介
博弈论是二人或多人在平等的对局中各自利用对方的策略变换自己的对抗策略,达到取胜目标的理论。博弈论是研究互动决策的理论。博弈可以分析自己与对手的利弊关系,从而确立自己在博弈中的优势,因此有不少博弈理论,可以帮助对弈者分析局势,从而采取相应策略,最终达到取胜的目的。博弈的类型分为:合作博弈、非合作博弈、完全信息博弈、非完全信息博弈、静态博弈、动态博弈,等等。
基础概念
必胜态:通过某一步可以转移到必败态的局面。 也就是说,对于一个处于必胜态的玩家,他总能找到一种合法操作,将当前局面变成一个必败态然后交给对方,如果中途不出现意外的话,最终自己就会得到胜利。但是处于必胜态并不意味着任意的操作都能将当前局面变成必败态。
必败态:通过某一步只能转移到必胜态的局面。 也就是说,处于必败态的玩家无论做什么操作,都只会将当前的局面变成必胜态,然后交给对方,只要对方足够聪明,那么该玩家将输掉比赛。
对于足够聪明的两个博弈者来说,游戏的胜负在比赛前就已经知道(当然,我这里只是说在题目里,在现实中如果是稍微复杂一点的博弈游戏,单凭人脑是很难达到那种水平),也就是说胜利的一方总能找到胜利的路径,而输掉的那一方无论怎样走,胜利的一方都能找到对应的方法。也就是说先后手以及起始局面可以决定整场博弈的胜负。
巴什博弈
只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者得胜。
求r=n%(1+m),判断r是否等于0,如果r不等于0,先手必胜,否则后手必胜。为什么?
我们可以分析一下,对于n=(1+m)*r+s,如果s不等于0的话,先手取走s,那么总的物品数剩下(1+m)*r,然后后手取走k的话,先手只要取走1+m-k的物品,就可以保持n=(1+m)的倍数的局面交给对方,这意味着什么?意味着n=0的局面最终会被后手得到,那样后手就输了。而如果s等于0的话,那么对于先手取k的物品,后手只要取1+m-k个物品就可以将n=0的局面转给先手,先手就输了。
所以这里的必败态是(1+m)的倍数。有没有发现,对于一场博弈来说,所有的必败态都会有相似的地方,就像这里,必败态一定是(1+m)的倍数。
然后再说深一点的巴什博奕:只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取p个,最多取q个,如果剩下的物品数小于p的话需要一次取完。最后取光者得胜。
这个又怎样求?按照上面的思路,我们可以得到公式n=(p+q)*r+s。
那么这里的s有两种情况①s>=p,②s<p,。
对于①很容易分析,只要先手取走s的话,对于后手去k,先手只要取p+q-k即可保证先手必胜。
对于②,分析起来没有①那么简单,所以这可能就一定需要用后面讲到的用SG值来判断了。
然后在讲一下一个问题。如果条件和基本的巴什博奕基本一样,但是说的是最后谁是无法再取物品的是赢家的话,那该怎么处理呢?
既然是这样,先手只要判断一下能不能将最后一步留给自己就可以了。而最后一步最少也要保留一个物品,所以我们可以将这个问题转化为基本的巴什博奕,只是终点变成一个物品,而不是零个物品。所以判断的条件是(n-1)%(1+m)!=0 ? 先手赢 : 后手赢。
nim和模型
有若干堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
假设这里有n堆物品,每一堆的数量分辨是a1,a2,a3,```,an。
那么如果ans=a1^a2^a3^```^an!=0,那么就是先手必胜,否则就是后手必胜。
这里我们需要用到二进制的思想。首先我们用必胜态和必败态的定义来证明一下。
首先,根据题意,只要还有物品,玩家就一定要取,而且每一次操作以后,物品的数目必定会减少。
对于必败态,也就是ans=0,那就说明a1^a2^a3^```^an=0,令a1,a2,a3```,an中,ai为某一堆物品的数量,ai^m=a1^a2^a3```^ai^```^an=0。我们从ai里面取走物品,那么ai-->ai‘最终ai‘^m必然不等于零,即转为必胜态,符合必败态的定义。(感觉证明不算很严谨······)
对于必胜态,如果此时的状态为aj^p=q(p等于除了aj以外的其他a[]的异或和),假设我们从aj上面取一定数目的物品使得aj-->aj‘,最终使aj‘^p=0的话,那么我们可以得到:
aj‘^p^q=q ---> aj^aj‘^p^p=q ---> aj^aj‘=q
这意味着什么,因为我们是从aj那里取走一定的物品以后变成aj‘的,这里取走的个数可能有很多种方法,但是,如果我们取走的个数是二的次幂这么多呢?很明显q就是我们需要从aj上面取走的个数了。只要当前的玩家从某一堆物品个数比q大的堆上取走q个物品,那么就可以将当前状态转化为必败态,并且转个对方。所以要保证先手必胜的条件就是a1^a2^a3^``````^an!=0。
SG函数(引用一下别人的ppt上面的解释)
定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。
对于一个给定的有向无环图,定义关于图的每个顶点的SG函数g如下:g(x)=mex{ g(y) | y是x的后继 }。
当g(x)=k时,表明对于任意一个0<=i<k,都存在x的一个后继y满足g(y)=i。也就是说,当某枚棋子的SG值是k时,我们可以把它变成0、变成1、……、变成k-1,但绝对不能保持k不变。这可以和nim游戏进行类比,一个有k个物品的堆,我们也可以把它变成0、变成1、……、变成k-1,但绝对不能保持k不变,因此一个游戏的SG函数就等于他若干个子游戏的SG值的异或和。
之所以引用别人ppt上的解释,主要是现在我对SG函数的认识还不是非常深刻,只能算大概是怎么回事,如果要用的话,大概要怎么用而已。这里比较有用的除了对SG的解释以外,还有就是一个游戏的SG函数等于它的若干个游戏的SG值的异或和。个人认为这所以可以这样使用是因为子游戏与子游戏之间斌没有相互影响,而这些子游戏就是一个大的Nim模型里面的不同堆物品。为什么可以比喻成Nim模型?因为这和SG函数的定义基本上可以等价,在SG函数的定义里,对于每一个x它都有其后继(除了x=0),所以sg[x]=k的含义就是对于sg[]=0~k-1的不同局面,x都可以到达,当然x还有可能可以到达比k还要大的局面,但是这里只需要考虑0~k-1的局面即可。正因为我们据需要考虑比k还要大的局面,所以我们才可以将SG函数用Nim的思想来计算。
关于怎样求SG值,这里给出一个大致的流程:
int sg[MAX]; //保存sg值的数组bool f[MAX]; //用于标记可转移到的后继的数组void solve(int n){ sg[0]=0; for(int i=1;i<=n;i++){ memset(f,0,sizeof(f)); /* 关于怎样进行状态(局面)转移的描述,将对于sg值等于i的所有可以转移到的后继的(sg[])都标记成f[ sg[] ]=1; */ for(int j=0;j<=n;j++){ if(!f[j]){ sg[i]=j; break; } } }}
关于博弈的题目,因为做的还不算太多,当前大部分做过的题目都在该博客关于博弈的分类上面,在对博弈有更深了解以后再在这里补充。