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