1. 程式人生 > 實用技巧 >(組合遊戲)SG函式與SG定理詳解

(組合遊戲)SG函式與SG定理詳解

有一段時間沒記錄知識類的部落格了,這篇部落格就說一下SG函式和SG定理

什麼是組合遊戲

在競賽中,組合遊戲的題目一般有以下特點

  1. 題目描述一般為Alice、Bob 2人做遊戲
  2. Alice、Bob交替進行某種遊戲規定的操作,每操作一次,選手可以在有限的操作(操作必須合法)集合中任選一種。
  3. 對於遊戲的任何一種可能的局面,合法的操作集合只取決於這個局面本身,不取決於其它因素(跟選手,以前的所有操作無關)
  4. 如果當前選手無法進行合法的操作,則為負

舉個例子現在有一個數0,小明小紅2人每次可以輪流在當前數加 1~3,誰先湊到21誰就贏

這個描述就符合上面的條件:

  • 小明小紅(滿足1)
  • 每次輪流在當前數上加1~3(滿足2)
  • 當前能進行的操作只取決於這個數本身(也就是這個局面),如果這個數為20,可操作的集合為+{1},如果為12,可操作的集合為+{1,2,3}(滿足3)
  • 如果數字已經為21了,則不可能往上在加數字,可操作集合為\(Φ\),當前選手為負(滿足4)

必勝點和必敗點的概念

  • 必敗點(P點) 前一個(previous player)選手將取勝的點稱為必敗點
  • 必勝點(N點) 下一個(next player)選手將取勝的點稱為必勝點

比如現在數字已經為18了,那麼當前操作人只要給數字+3則必勝,我們就把在此位置稱為必勝點(正常操作情況下,別槓說都18偏要+2。。。。)
必勝點和必敗點的性質:
- 所有的終結點都是必敗點
- 從任何必勝點操作,至少有一種方式進入必敗點
- 無論如何操作, 從必敗點都只能進入必勝點.

Sprague-Grundy(SG)定理

遊戲和的SG函式等於各個遊戲SG函式的Nim和。這樣就可以將每一個子遊戲分而治之,從而簡化了問題。而Bouton定理就是Sprague-Grundy定理在Nim遊戲中的直接應用,因為單堆的Nim遊戲 SG函式滿足 SG(x) = x。

Nim和 : 各個數相異或的結果

SG函式

先定義mex(minimal excludant)運算,這是施加於一個集合的運算,表最小的不屬於這個集合的非負整數。例如\(mex\{0,1,2,4\}=3、mex\{2,3,5\}=0、mex\{\}=0\)
對於任意狀態 x , 定義 SG(x) = mex(S),其中 \(S\)

\(x\) 後繼狀態的 \(SG\)函式值的集合。如 x 有三個後繼狀態分別為 \(SG(a),SG(b),SG(c)\) ,那麼 \(SG(x) = mex\{SG(a,SG(b),SG(c)\}\) 。這樣集合 \(S\)

的終態必然是空集,所以\(SG\) 函式的終態為 \(SG(x) = 0\) ,當且僅當x 為必敗點P時

取石子問題

有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;

以此類推…

x 0 1 2 3 4 5 6 7 8…

SG[x] 0 1 0 1 2 3 2 0 1…

由上述例項我們就可以得到SG函式值求解步驟,那麼計算1~n的SG函式值步驟如下:

1、使用 陣列f 將 可改變當前狀態 的方式記錄下來。

2、然後我們使用 另一個數組 將當前狀態x 的後繼狀態標記。

3、最後模擬mex運算,也就是我們在標記值中 搜尋 未被標記值 的最小值,將其賦值給SG(x)。

4、我們不斷的重複 2 - 3 的步驟,就完成了 計算1~n 的函式值。
模板如下:

//f[N]:可改變當前狀態的方式,N為方式的種類,f[N]要在getSG之前先預處理
//SG[]:0~n的SG函式值
//S[]:為x後繼狀態的集合
int f[N],SG[MAXN],S[MAXN];
void  getSG(int n){
    int i,j;
    memset(SG,0,sizeof(SG));
    //因為SG[0]始終等於0,所以i從1開始
    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;  //將後繼狀態的SG函式值進行標記
        for(j = 0;; j++) if(!S[j]){   //查詢當前後繼狀態SG值中最小的非零值
            SG[i] = j;
            break;
        }
    }
}

其實不難發現,Nim遊戲就是一個很典型的用SG定理解決的問題,因為Nim遊戲在一堆n個石子中可以取1-n個石子,所以單獨這一堆石子的SG值為\(mex(n−1,n−2,n−3,...,n−n)=n\),根據SG定理,每一堆石子總數相互異或即為答案


本文是參考其他博文+自己理解,整理而來,現附上參考博文連結:
https://blog.csdn.net/luomingjun12315/article/details/45555495
https://blog.csdn.net/SM_545/article/details/77340690