我的理解:SG函數是人們在研究博弈論的道路上邁出的重要一步,它把許多雜亂無章的博弈遊戲經過某種規則結合在了一塊兒,使得一類廣泛的博弈問題獲得瞭解決。php
從SG函數開始,咱們再也不是單純的同過找規律等方法去解決博弈問題,而是須要學習一些博弈論中基本的定理,來找到他們的共同特色html
那麼就先介紹幾個最基本的定理(也能夠叫常識)吧函數
1.遊戲有兩我的參與,兩者輪流作出決策。且這兩我的的決策都對本身最有利。學習
2.當有一人沒法作出決策時遊戲結束,沒法作出決策的人輸。不管兩者如何作出決策,遊戲能夠在有限步內結束。spa
3.遊戲中的同一個狀態不可能屢次抵達。且遊戲不會有平局出現。任意一個遊戲者在某一肯定狀態能夠做出的決策集合只與當前的狀態有關,而與遊戲者無關。code
知足上述條件的問題咱們稱之爲ICG遊戲,ICG遊戲屬於組合遊戲htm
最典型的nim遊戲,就是一種ICG遊戲blog
定義P-position與N-position遊戲
P-position:必敗態(簡記爲P
),即Previous-position,你能夠直觀的認爲處於這種狀態的人必定會輸terminal
N-position:必勝態(簡記爲N
),即Next-position,你能夠直觀的理解爲處於這種狀態的人必定會贏
這僅僅是最直觀的定義
更嚴謹的定義爲:
能夠
移動到P的局面爲N全部
移動都會進入N的局面爲P在正式研究\(SG\)函數以前,咱們先來研究一下DAG中的博弈
給定一張有向無環圖,在起始定點有一枚棋子,兩個頂尖聰明的人交替移動這枚棋子,不能移動的人算輸
不要小看這個遊戲,事實上,全部ICG問題均可以抽象爲這種遊戲(即把初始局面看作頂點,把從一個狀態能夠到另外一個狀態之間連邊)
下面咱們來正式研究一下SG(Sprague-Grundy)函數
首先定義mex
運算,這是一種集合中的運算,它表示最小的不屬於集合的非負整數
例如\(mex\{1,2,3\}=0\),\(mex\{0,2\}=1\),\(mex\{0,1,2,3\}=4\),\(mex\{\}=0\)
對於給定的有向無環圖,定義每一個點的SG函數爲
\(SG(x)=mex \{\ SG(y)\ |\ x \ can\ go\ to\ y \}\)
然而單單一個這樣的空洞的函數是解決不了問題的,咱們須要分析一下它的性質
這個性質比較顯然,由於匯點的全部後繼狀態都是空集
由\(SG\)函數的性質易知該節點的全部後繼節點\(SG\)值均不爲\(0\)
知足必敗態的定義
由\(SG\)函數的定義可知該節點的後繼節點中必定有一個節點\(SG=0\)
知足必勝態的定義
這樣咱們經過最基本的\(SG\)值的定義,咱們就能夠判斷出一個狀態是必勝態仍是必敗態
這個問題實際上就是咱們前面講的巴什博奕
若是這個問題再複雜一點呢?
當這個棋盤上有\(n\)個棋子的時候呢?
其實它們的分析思路是同樣的
當\(SG(x)=k\)時,它代表後繼狀態中含有\(SG(y)=1 \dots k-1\)
也就是說,咱們從\(k\)能夠轉移到\(1 \dots k-1\)中的任何一個狀態,而當前共有\(n\)個棋子。
這會讓你想到什麼?
nim取石子游戲!
那咱們是否是也能夠推出:
若是在nim遊戲中的\(n\)堆石子的\(SG\)值異或和不爲\(0\)就說明先手必勝呢?
這是確定的,由於當你打出nim遊戲的\(SG\)值表時就會發現,\(SG_{nim}(x)=x\)
是否是很神奇?
SG函數的應用遠遠不止和巴什博奕與nim遊戲有關,咱們回過頭來考慮可否把SG函數推廣開來
類比nim取石子游戲的思路,咱們可不能夠大膽設想:
遊戲的和的SG值是他們的SG值的xor
暫且無論這個結論對不對,咱們設想一下,假如這個結論對的話,會有什麼後果.
咱們能夠將ICG問題對應到DAG上,而後直接經過SG函數之間的轉移而解決幾乎所有的問題
是否是很使人興奮?
更使人興奮的是,這個定理是正確的!
什麼?證實?
若是你是一個追求完美的人能夠看這裏
若是你像我同樣連線性代數都不知道是什麼的話大概就是從DAG上概括一下就行了吧
SG定理的應用很是的普遍,幾乎全部的博弈類問題都有它的影子,本文僅僅是簡單的介紹一下這個定理,更深層次的應用之後會補充的
上面提到了SG函數,那麼SG函數的值是怎麼計算的呢?
很簡單,咱們直接經過\(mex\)運算的定義就能夠計算了
int F[MAXN];//能夠轉移的狀態集合,通常題目會給出 int S[MAXN];//表示該點能夠轉移到的狀態有哪些 int SG[MAXN];//該點的SG值 void GetSG() { for(int i=1;i<=N;i++)//枚舉DAG中全部點 { memset(S,0,sizeof(S));//初始化 for(int j=1;j<=limit&&F[j]<=i;j++)//limit表示轉移的集合的大小 S[SG[i-F[j]]]=1; for(int j=1;;j++) if(!S[j]) {SG[i]=i;break;}//根據定義計算SG函數 } }
來一道裸題