1. 程式人生 > >博弈論-SG函式和SG定理

博弈論-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;
}