(浅)博弈论学习笔记

 

两周前去学nim和sg函数,但是,又又又忘了QAQ

 

0,对nim游戏的定义是:两人,有若干堆石子,每堆石子数量是有限的(a1,a2,...,an),合法的移动时候:选择一堆石子并拿走若干颗(可以全拿,不能不拿)。如果轮到某人时,已无子可取,则为败,另一人为胜。

 

1,设P-position为先手必败(当前态为必败态)/后手可保证必胜;

2,设N-position先手可保证必胜(当前态为必胜态);

3,设游戏中无法进行任何移动的局面(terminal position)为P-position;

4,可以移动到P-position的局面是N-position(性质);

5,所有移动都导致N-position的局面是P-position(性质);

 

6,对nim有结论:对于一个nim游戏的局面(a1,a2,...,an),它是P-position当且仅当a1^a2^...^an==0(即,a1^a2^...^an!=0 为N-position);

 

7,判断6的正确性:

  (1),对于terminal position,a1=a2=...=an=0,有a1^a2^...^an=0,而对于定义terminal potion为P-position,成立。

  (2),假设6成立,则需满足N-position一定能移动到P-position(第4点),

      N-position为 a1^a2^...^an!=0 ,设 a1^a2^...^an!=k (k!=0),则一定存在某个ai,它的二进制表示的最高位1为k而进制表示的最高位1,在这时,当前 将ai(通过取石子)的值,变换为ai`=ai^k,则有:a1^a2^...^an^k=k^k=0,在假设6成立下性质满足。

  (3),假设6成立,则需满足P-position一定无法使下一个状态为P-position(第5点),

      P-position为 a1^a2^...^ai^...^an==0 ,则,显然 a1^a2^...^ai`^...^an!=0(ai`<ai)。

  所以6的正确性显然。

 

8,进一步,假设nim游戏有:每次最多只能取k个,的限制,则:将每堆石子数mod(k+1);。

 

9,SG函数:Sprague-Grundy函数:详见这个博客

  首先定义mex(局外最小序数)运算,对于一个集合S,mex(S)为,不是S的元素的最小一个序数(非负)。如:mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。

  给定一个有向无环图和一个起始顶点上的一枚棋子,两名选手交替的将这枚棋子沿有向边进行移动,无法移动者判负。

 

  对于一个给定的有向无环图,定义关于图的每个顶点的Sprague-Garundy函数g:g(x)=mex{ g(y) | y是x的后继 }。

  且定义:(1)叶子节点(terminal potsition)的SG值为0。

   则有:(2)对于一个g(x)==0的顶点x,它的所有后继y都满足g(y)!=0。

      (3)对于一个g(x)!=0的顶点x,它必有一个后继y满足g(y)==0。

  则,由上面3点,可知,顶点x所代表的position为P-position当且仅当g(x)==0(即,g(x)!=0为N-position)

 

  详见博客= =

 

  当面对由n个游戏组合成的一个游戏时,只需对于每个游戏找出它每个局面的SG值的方法,就可以把SG值全部看出nim的石子堆,再由nim的必胜策略判断必胜局面。

  SG值根据mex函数确定,具体方法为打表orDFS。

 

10,原文链接:https://blog.csdn.net/strangedbly/article/details/51137432

  解题模型

  (1)把原游戏分解成多个独立的子游戏,则原游戏的SG函数值是它的所有子游戏的SG函数值的异或。即sg(G)=sg(G1)^sg(G2)^...^sg(Gn)。

  (2)分别考虑没一个子游戏,计算其SG值。

   SG值的计算方法:(重点)

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

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

   3,可选步数为一系列不连续的数,用模板计算。

        模板1:打表

//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;
            }
        }
    }
}

  模板2:DFS

//注意 S数组要按从小到大排序 SG函数要初始化为-1 对于每个集合只需初始化1遍
//n是集合s的大小 S[i]是定义的特殊取法规则的数组
int s[110],sg[10010],n;
int SG_dfs(int x)
{
    int i;
    if(sg[x]!=-1)
        return sg[x];
    bool vis[110];
    memset(vis,0,sizeof(vis));
    for(i=0;i<n;i++)
    {
        if(x>=s[i])
        {
            SG_dfs(x-s[i]);
            vis[sg[x-s[i]]]=1;
        }
    }
    int e;
    for(i=0;;i++)
        if(!vis[i])
        {
            e=i;
            break;
        }
    return sg[x]=e;
}

 

上一篇:硬币博弈的SG值规律


下一篇:SG函数