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