博弈論之SG函數

SG函數

       首先定義一個基於集合的運算mex{a1,a2,a3....},運算的結果爲集合的整數補集中的最小自然數。

       對於一個給定的有向無環圖,定義關於圖的每個頂點的Sprague-Grundy函數g如下:

        g(x)=mex{ g(y) | y是x的後繼 }。

例:當前有n個石子,每次能取得石子集合爲f[]={1,2,3}。

      sg[0]=0;

      sg[1]=mex{sg(1-f[1])}=1;

      sg[2]=mex{sg(2-f[1]),sg(2-f[2])}=2;

      sg[3]=mex{sg(3-f[1]),sg(3-f[2]),sg(3-f[3])}=mex{sg(2),sg(1),sg(0)}=3;

      sg[4]=mex{sg(4-f[1]),sg(4-f[2]),sg(4-f[3])}=mex{sg(3),sg(2),sg(1)}=0;

      ............


SG函數模板1

<pre name="code" class="cpp">
<pre name="code" class="cpp"> //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

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



      

發佈了68 篇原創文章 · 獲贊 9 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章