博弈论-SG函数和SG定理

1.SG函数和SG定理是一个十分神奇的东西,有了它,绝大部分的博弈都可以被统一到这个上面,都可以使用SG函数解决。是一种解决博弈问题的十分方便的手段。

2.首先给出一些基本的定义:mex运算,这个是作用在集合上的运算,具体的含义就是:找出不属于当前集合最小的非负整数,可能你有点晕,我们看几个例子。mex{1,2,3}=0;为什么?因为自然数从0开始,不属于这个集合最小的非负整数就是0了,再例如mex{0,1,3}=2;根据上面的观点这个应该也是很好理解的吧。

3.元素x的后继状态:这个可能比较难以理解,什么叫做元素x的后继状态呢?其实就是x可以转移过去的状态。我们在Bash博弈中,可以取1-m个石子,当前有x个石子,所以x可以转移到的状态是{x-1,x-2,....x-m}这个集合的每一个元素叫做x的后继状态。

4.SG函数:对于任意的状态x,我们定义函数SG(x)=mex(S),其中S的X的后继状态的集合。

5.SG定理:游戏和的SG函数等于各个游戏SG函数的Nim和。(NIm和就是每个SG函数值异或起来)。

6.SG函数值和博弈结果的关系:(1)在一个游戏中有n个物品,如果SG(n)=0,先手必败,否则先手必胜。(2)n个游戏组成的一个游戏(可以看做n堆物品),游戏和的SG函数等于0,先手必败,否则先手必胜。

7.实际的例子:SG函数的使用。这个例子不像传统的四大博弈一样直接有结论可用,其实这个有点像Nim博弈,但是拿去物品数量的限制使得这个题不能使用Nim博弈的结论,所以这个时候SG函数就十分有用了。我们先简单的分析一下SG函数的使用步骤

1、使用 数组S将 可改变当前状态 的方式记录下来。(其实就是可以拿取多少物品的集合)

2、然后我们使用 另一个数组 将当前状态x 的后继状态标记。

3、最后模拟mex运算,也就是我们在标记值中 搜索 未被标记值 的最小值,将其赋值给SG(x)。

4、我们不断的重复 2 - 3 的步骤,就完成了 计算1~n 的函数值。

下面是AC的代码:

#include<bits/stdc++.h>
#define MAXN 1000 + 10
#define N 20
int f[N], SG[MAXN], S[MAXN];
void getSG(int n) {
	int i, j;
	memset(SG, 0, sizeof(SG));
	for (i = 1; i <= n; i++)
	{
		memset(S, 0, sizeof(S));
		for (j = 0; f[j] <= i && j < N; j++)
			S[SG[i - f[j]]] = 1;
		for (j = 0;; j++) if (!S[j]) 
		{
			SG[i] = j;
			break;
		}
	}
}
int main() {
	int n, m, k;
	f[0] = f[1] = 1;
	for (int i = 2; i <= 16; i++)
		f[i] = f[i - 1] + f[i - 2];
	getSG(1000);
	while (scanf("%d%d%d", &m, &n, &k), m || n || k) {
		if (SG[n] ^ SG[m] ^ SG[k]) printf("Fibo\n");
		else printf("Nacci\n");
	}
	return 0;
}


 

猜你喜欢

转载自blog.csdn.net/weixin_41863129/article/details/85466273