SG函数和SG定理

SG定理:
**游戏和的SG函数等于各个游戏SG函数的Nim和。**意思就是例如对Nim游戏,各个游戏的SG函数也就是每一堆石子的数量即SG(x)=x.那么游戏和的SG函数就是对各个游戏SG函数进行异或求得Nim和。

SG函数:

首先定义mex运算,这是施加于集合得运算,表示最小的不属于这个集合的非负整数,例如mex{0,1,2,4}=3、mex[2,3,5]=0.
对于任意状态x,定义SG(x)=mex(S),其中S是x的后续状态的集合。例如x有三个后续状态分别为SG(a),SG(b),SG©,那么SG(x)=mex(SG(a),SG(b),SG©),对于SG(0)来说它没有后续状态那么它的值就是0.

取石子问题:

有1堆含n个石子,每次只能取[1,3,4]个石子,先取完石子者获胜,那么各个数的SG函数为多少?
SG[0]=0, f[]={1,3,4};
x=1时,可以取走1-f[1]个石子,剩余{0}个,所以SG[1]=mex{SG[0]}=mex{0}=1;
x=2 时,可以取走2 - f{1}个石子,剩余{1}个,所以 SG[2] = mex{ SG[1] }= mex{1} = 0;
x=3 时,可以取走3 - f{1,3}个石子,剩余{2,0}个,所以 SG[3] = mex{SG[2],SG[0]} = mex{0,0} =1;
x=4 时,可以取走4- f{1,3,4}个石子,剩余{3,1,0}个,所以 SG[4] = mex{SG[3],SG[1],SG[0]} = mex{1,1,0} = 2;
x=5 时,可以取走5 - f{1,3,4}个石子,剩余{4,2,1}个,所以SG[5] = mex{SG[4],SG[2],SG[1]} =mex{2,0,1} = 3;
以此类推…

由上述实例我们就可以得到SG函数值求解步骤,那么计算1~n的SG函数值步骤如下:
1、使用 数组f 将 可改变当前状态 的方式记录下来。
2、然后我们使用 另一个数组 将当前状态x 的后继状态标记。
3、最后模拟mex运算,也就是我们在标记值中 搜索 未被标记值 的最小值,将其赋值给SG(x)。
4、我们不断的重复 2 - 3 的步骤,就完成了 计算1~n 的函数值。

//f[N]当中记录的是可改变当前状态的方式
//SG[N]记录0~n的SG函数值
//S[]记录的是x的后继状态
int f[N],SG[MAXS],S[MAXS];
void getSG(int n){
	memset(SG,0,sizeof(SG));
	//因为i=0的时候SG[0]=0,所以从1开始
	for(int i=1;i<=n;i++){
	//每次都要将上一状态的后继集合重置
	    memset(S,0,sizeof(S));
	    for(int j=0;f[j]<=i&&j<N;j++){
		S[SG[i-f[j]]]=1;//将后继状态进行标记
	    }
	    for(int j=0;j<MAXS;j++){
		if(!S[j]){
			SG[i]=j;
			break;
	        }
	    }
	}
}

对于SG函数的理解:
首先,一个点的子状态可能有多个,然后每个子状态又会有自己的子状态。当一个状态的子状态可以判断必胜还是必败的时候,子状态返回自己的SG值,然后用一个vis数组存下来,然后当当前状态的所有子状态都返回了自己的SG值,那么vis从0开始,第一个没有被标记过的自然数就是当前状态的SG值。
当一个值被vis数组记录过,说明当前状态可以转换成对应sg值的状态,那么,如果0被标记了,那么说明当前状态可以转换成必败态,那么当前状态一定是非0的,也就是必胜态。mex函数也就是寻找第一个不能转换到的状态,那么,只需要关注0和非0即可。意思是,当你通过vis数组找到的当前点的SG值为0则说明,当前点没有没有办法转换的必败态,那么当前点就是必败态,所有SG函数的值为0,反之,就是当前点可以一步到达必败态,那么此时就是必胜态。
当所有点的SG的值都推出来的时候,答案一般就是所求点的SG值得异或,异或为0先手必败,反之先手必胜。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值