1. 程式人生 > >再談SG函式和SG定理

再談SG函式和SG定理

今天考了一道博弈論的題,讓我重新複習一下SG定理吧。
首先通常的Nim遊戲的定義是這樣的:有若干堆石子,每堆石子的數量都是有限的,合法的移動是“選擇一堆石子並拿走若干顆(不能不拿)”,如果輪到某個人時所有的石子堆都已經被拿空了,則判負(因為他此刻沒有任何合法的移動)。

我們知道對於最普通最一般的NIM取石子來說,所有石子個數異或起來如果為0,那麼先手必敗,如果不為0那麼先手必勝。

具體證明如下:

1、最後的遊戲狀態必然是所有石子個數為0,也可以看成所有石子異或為0。
2、假如現在所有石子異或起來為J,我們用Ai表示第i堆石子個數,總共n堆。那麼就有A1^A2^A3……^An=j,我們把j二進位制表示,則A中必有一個數最高位與j的最高位同為1(位數一樣),不然j的那個1是哪來的?然後我們令這個數是Am,所以Am^j必然小於Am,顯然最高位被消掉變小了。我們可以取石子把Am變成Am^j,那麼對於原式就是A1^A2^……^An^j=j^j=0;
3、如果異或起來為0,那麼如果任意拿掉石子,新的異或一定不為0,這個證明十分簡單,留給讀者解決。(偷懶~)

所以當異或不為0的時候,都可以通過操作讓它變成0,所以顯然就有了上面那個結論。

那麼現在我們上重頭。

對於一個大的遊戲,我們把它看成是多個小的遊戲,比如這個取石子,我們把它看成是n個小的遊戲。
現在我們單獨考慮一個遊戲,也就是一堆石子如何解決。
我們規定一個對於集合的操作mex,表示最小的不屬於該集合的非負整數。
舉幾個栗子:mex{0,1,2}=3,mex{1,2,3}=0,mex{0,1,3}=2;

我們再定義SG函式:SG(x)=mex{ SG(y) | y是x的後繼 }。
什麼叫y是x的後繼?我們用普通的NIM遊戲舉個栗子。假如有一堆石子個數為x,普通的NIM遊戲可以取任意個,但不能一個不取,所以x的後繼就是0~x-1,所以y取值0~x-1。
有一個結論就是普通的取石子SG(x)=x。

我們考慮SG函式的性質,我們把遊戲看成一個圖,那麼其實就是一個點在這張圖上面跑,當這個點走到0的時候它就走不動了。SG值為0時,表示當前點為必敗點,因為它下面的SG值都大於0。SG值大於0,當前點是必勝點,因為它可以走到一個點的SG值為0。
所以得到結論SG值為0就是必敗,SG大於0就是必勝。

我們已經考慮完了單個遊戲,那麼我們考慮把遊戲合起來考慮。
合起來的遊戲其實相當於n個點同時在這張圖上面跑。
這裡還有一個SG函式的性質,如果SG(x)=y,那麼它可以走到的後繼的SG值有0-y-1,參考它的定義。這裡是不是有點熟悉?這不就相當於最普通的NIM取石子嗎?可以取任意個,但不能一個不取。我們把SG值看成石子個數,那麼整個遊戲的SG值就是子游戲的SG值異或的和。

至此我們可以得到對於這類題,普遍的解法了。先打出SG函式找規律然後異或就完了。

給出一個找SG函式的模板:(其實就是模擬SG函式的定義)

int f[N],SG[N],S[N];  
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;  
        }  
    }  
}  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
					<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-a47e74522c.css" rel="stylesheet">
            </div>

今天考了一道博弈論的題,讓我重新複習一下SG定理吧。
首先通常的Nim遊戲的定義是這樣的:有若干堆石子,每堆石子的數量都是有限的,合法的移動是“選擇一堆石子並拿走若干顆(不能不拿)”,如果輪到某個人時所有的石子堆都已經被拿空了,則判負(因為他此刻沒有任何合法的移動)。