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