SG函数

Sprague-Grundy定理(SG定理):

游戏和的SG函数等于各个游戏SG函数的Nim和。这样就可以将每一个子游戏分而治之,从而简化了问题。而Bouton定理就是Sprague-Grundy定理在Nim游戏中的直接应用,因为单堆的Nim游戏 SG函数满足 SG(x) = x。

SG函数:

首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。

对于任意状态 x , 定义 SG(x) = mex(S),其中 S 是 x 后继状态的SG函数值的集合。如 x 有三个后继状态分别为 SG(a),SG(b),SG(c),那么SG(x) = mex{SG(a),SG(b),SG(c)}。 这样 集合S 的终态必然是空集,所以SG函数的终态为 SG(x) = 0,当且仅当 x 为必败点P时。
 

解题模型:

1. 把原游戏分解成多个独立的子游戏,则原游戏的SG函数值是它的所有子游戏的SG函数值的异或。

       即sg(G) = sg(G1) ^ sg(G2) ^ ... ^ sg(Gn)

2. 分别考虑每一个子游戏,计算其SG值。

3. 若sg(G)=0,则为P-Position(必败态),否则为N-Position(必胜态)。

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

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

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

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

int F[100];//一系列不一定连续的数,下标从1开始 
 
inline void BuildF(){
	
}

int SG[MAXN];
bool SGhash[MAXN];
 
inline int getSG(int x){
	memset(SGhash,false,sizeof SGhash);
	for(int j=1 ; j<100 && F[j]<=x ; ++j){
		SGhash[SG[x-F[j]]] = true;
	}
	for(int j=0 ; j<MAXN ; ++j){
		if(!SGhash[j])return j;
	}
	return -1;
}

inline void BuildSG(int x){
	memset(SG,0,sizeof SG);
	for(int i=1 ; i<=x ; ++i){
		SG[i] = getSG(i);
	}
}
原文地址:https://www.cnblogs.com/vocaloid01/p/9513998.html