博弈—SG

来源:互联网 发布:直通车重要数据 编辑:程序博客网 时间:2024/05/24 07:02


组合游戏之基础博弈:http://blog.csdn.net/m0_37345402/article/details/77198270



Sprague-Grundy(SG)

SG值: 除 任意一步所能转移到的子局面的SG值以外的最小非负整数。 

SG定理:
游戏和的SG函数等于各个游戏SG函数的Nim和。假如说在一个游戏中有多个石子堆,我们只需要把对每个石子堆进行sg函数的调用,将得到的所有的值进行
异或。得出来的结果为0则局面为必败态。否则为必胜态。

SG函数:
可以将sg函数看作是一个深搜的的过程。而每一堆的石子就相当于图中间的节点,(状态为点,决策为边)所以说整个sg函数的过程就是在对一个有向无环图进行dfs的过程。终止状态出度为0.

定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。例如 mex{}=0,mex{0,1,2,4}=3,mex{2,3,5}=0。
sg[x] =mex{sg[y] | y是x的后继}    y是x的后继,即x下一步可以到达的状态y


eg.取石子问题
一堆n个的石子,每次只能取{1,3,4}个石子,先取完石子者获胜,求各个数的sg值。
sg[0]=0, f[]={1,3,4}
n=1时,可以取走1 - f{1}个石子,剩余{0}个,所以 sg[1] = mex{ sg[0] }= mex{0} = 1;
n=2,可以取走2 - f{1}个石子,剩余{1}个,所以 sg[2] = mex{ sg[1] }= mex{1} = 0;
n=3,可以取走3 - f{1,3}个石子,剩余{2,0}个,所以 sg[3] = mex{sg[2],sg[0]} = mex{0,0} =1;
n=4,可以取走4 - f{1,3,4}个石子,剩余{3,1,0}个,所以 sg[4] = mex{sg[3],sg[1],sg[0]} = mex{1,1,0} = 2;
n=5,可以取走5 - f{1,3,4}个石子,剩余{4,2,1}个,所以sg[5] = mex{sg[4],sg[2],sg[1]} =mex{2,0,1} = 3;
.....

   x     0  1  2  3  4  5  6  7  8....

sg[x]  0  1  0  1  2  3  2  0  1....

打表模板


void get_sg(){memset(sg,0,sizeof(sg));int i,j;for(i=1;i<=n;i++)//sg[0]=0,所以i从1开始,打表1-n个石子。 {memset(math,0,sizeof(math));//math[]保存所有后继值//a[t]表示改变当前状态的方式,即每次可取的值,t为方式的种类 for(j=0;a[j]<=i&&j<=t;j++){math[sg[i-a[j]]]=1;//把后继状态的sg函数值标记为1 }for(j=0;j<=n;j++)  //模拟mex运算 {if(math[j]==0)//查询后继状态sg值中最小的非零值 {sg[i]=j;break;}}}}

dfs 递归模板

int get_sg(int x)    {       int i;if(sg[x]!=-1)   return sg[x]; bool math[10005];//定义在里面!     memset(math,0,sizeof(math));        for(i=0;i<t&&f[i]<=x;i++)        {            get_sg(x-f[i]);        math[sg[x-f[i]]]=1;              }         for(i=0;;i++)         {            if(math[i]==0)            {        sg[x]=i;        break;}        }       return sg[x];   }  




















原创粉丝点击