博弈知识(三)

首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小属于这个集合的非负整数

例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0

对于一个给定的有向无环图,定义关于图的每个顶点的Sprague-Grundy函数g如下:

                             g(x)=mex{ g(y) | y是x的后继 } ( 这里的g(x)即sg[x])

用语言来描述就是:g(x)的值等于所有x的后继的SG函数中没有出现的最小非负整数。

 

例如:取石子问题,有1堆n个的石子,每次只能取{1,3,4}个石子,先取完石子者胜利,那么各个数的SG值为多少?

sg[0]=0,f[]={1,3,4},

x=1时,可以取走1-f{1}个石子,剩余{0}个,mex{sg[0]}={0},故sg[1]=1;

x=2时,可以取走2-f{1}个石子,剩余{1}个,mex{sg[1]}={1},故sg[2]=0;

x=3时,可以取走3-f{1,3}个石子,剩余{2,0}个,mex{sg[2],sg[0]}={0,0},故sg[3]=1;

x=4时,可以取走4-f{1,3,4}个石子,剩余{3,1,0}个,mex{sg[3],sg[1],sg[0]}={1,1,0},故sg[4]=2;

x=5时,可以取走5-f{1,3,4}个石子,剩余{4,2,1}个,mex{sg[4],sg[2],sg[1]}={2,0,1},故sg[5]=3;

以此类推.....

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

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

 

计算从1-n范围内的SG值。

f(存储可以走的步数,f[0]表示可以有多少种走法)

f[]需要从小到大排序

1.可选步数为1~m的连续整数,直接取模即可,SG(x) = x % (m+1);

2.可选步数为任意步,SG(x) = x;

3.可选步数为一系列不连续的数,用GetSG()计算

 

模板:

1,打表

//f[]:可以取走的石子个数
//sg[]:0~n的SG函数值
//hash[]:mex{}

int f[maxn],n;//n代表集合元素的个数
int sg[maxn];
bool hash[maxn];

void getsg()
{
    memset(sg,0,sizeof(sg));
    for(int i=1;i<=maxn;i++)
    {
        memset(hash,0,sizeof(hash));
        for(int j=1;j<=n;j++)
        {
            if(i>=f[j])
             hash[sg[i-f[j]]]=1;
        }
        for(int j=0;j<=maxn;j++)
        {
            if(hash[j]==0)
            {
                sg[i]=j;
                break;
            }
        }
    }
}

 

2、dfs

//f[]:可以取走的石子个数
//sg[]:0~n的SG函数值
//hash[]:mex{}
int f[N],sg[N],hash[N];     
void getSG(int n)
{
    int i,j;
    memset(sg,0,sizeof(sg));
    for(i=1;i<=n;i++)
    {
        memset(hash,0,sizeof(hash));
        for(j=1;f[j]<=i;j++)
            hash[sg[i-f[j]]]=1;
        for(j=0;j<=n;j++)    //求mes{}中未出现的最小的非负整数
        {
            if(hash[j]==0)
            {
                sg[i]=j;
                break;
            }
        }
    }
}

 

posted @ 2016-12-01 19:24  邻家那小孩儿  阅读(113)  评论(0编辑  收藏  举报