SG函数
(mex)运算:(mex)运算是一个施加于集合的运算,表示最小的不属于这个集合的非负整数。例如(mex{0,1,3}=2,mex{1}=0,mex{}=0)
(SG)函数:对于任意状态(x),(SG(x)=mex({SG(y)|y是x的后继状态}))
当(SG(x)==0)时(x)为必败态,(SG(x)
eq 0)时(x)为必胜态
(SG)函数的计算可以使用动态规划或者记忆化搜索,设状态数的最大值为(n),转移数为(m),则时间复杂度(O(n*m))
模板:动态规划计算([0,n])的SG函数值
int SG[maxn],S[maxn],f[maxm];
void get_SG(int n,int m){
int i,j;
memset(SG,0,sizeof(SG));
for(i=1;i<=n;i++){
memset(S,0,sizeof(S));
for(j=0;j<m && f[j]<=i;j++)
S[SG[i-f[j]]]=1;
j=0;
while(S[j]!=0) j++;
SG[i]=j;
}
}
相关题目:hdu1536 S-Nim
记忆化搜索计算(SG)函数,虽然每堆石子数最多为(10000),但是由于转移数最多为(100),所以(SG)函数的值不超过(100),可以开大小为(110)的(S)数组
#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<algorithm>
#define LL long long
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define pi acos(-1.0)
#define lowbit(x) x&(-x)
using namespace std;
int number_s,s[110],T,number_a,a[110],SG[10010];
int f(int x){
if(SG[x]!=-1) return SG[x];
bool S[110];
for(int i=0;i<=100;i++) S[i]=0;
for(int i=1;i<=number_s && x-s[i]>=0;i++){
S[f(x-s[i])]=1;
}
int i=0;
while(S[i]) i++;
return SG[x]=i;
}
int main(void){
while(scanf("%d",&number_s)!=EOF && number_s){
for(int i=1;i<=number_s;i++){
scanf("%d",&s[i]);
}
sort(s+1,s+1+number_s);
scanf("%d",&T);
memset(SG,-1,sizeof(SG));
SG[0]=0;
while(T--){
scanf("%d",&number_a);
int ans=0;
for(int i=1;i<=number_a;i++){
scanf("%d",&a[i]);
ans^=f(a[i]);
}
if(ans) printf("W");
else printf("L");
}
printf("
");
}
return 0;
}
SG定理
(SG)定理:游戏和的(SG)函数等于各个游戏的(SG)函数的异或和
(SG)函数表示除了后继状态(SG)函数值以外的最小值,也就是从(SG(x)=k)的状态可以转移到(0,1,cdots,k-1)的所有状态。这和(NIM)博弈相同,所以可以通过异或和判断胜败。