SG函數起源於一個經典的問題如下:
給定一個有向無環圖和一個起始頂點上的一枚棋子,兩名選手交替的將這枚棋子沿有向邊進行移動,無法移 動者判負。事實上,這個遊戲可以認爲是所有Impartial Combinatorial Games(公平組合遊戲)的抽象模型。也就是說,任何一個ICG都可以通過把每個局面看成一個頂點,對每個局面和它的子局面連一條有向邊來抽象成這個“有向圖遊戲”。下 面我們就在有向無環圖的頂點上定義Sprague-Grundy(簡稱SG)函數。
首先定義mex(minimal excludant)運算,這是施加於一個集合的運算,表示最小的不屬於這個集合的非負整數。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0,而sg(x) = mex ( sg(y) |y是x的後繼結點 )。
所謂後繼結點就是當前結點經過一個操作可以變成的狀態。比如對於取石子游戲,假如每次可以取的數目是1,2,4,當前的石子數目也就是當前狀態是5,那麼5的後繼結點就是{5-1, 5-2, 5-4}={4,3,1};如果5的三個後繼結點的SG函數值分別爲0,1,3,那麼5的SG值就是集合{0,1,3}的補集的最小元素,也就是2。
關於整個遊戲的sg值之和sum,定義sum=sg1 ^ sg2 ^ sg3 ^ ……sgn. 其中^表示按位異或運算。
結論:一個遊戲的初始局面是必敗態當且僅當sum=0。
關於SG函數的計算分三種情況:
- 可選步數爲1~m的連續整數時,直接取模即可,SG(x)=x%(m+1);
- 可選步數爲任意步時,SG(x) = x;
- 可選步數爲一系列不連續的整數時,只能按部就班用getSG()函數求解。
下面給出一個SCDN上的一個具體編程例子:
AC代碼如下(java):
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while(in.hasNext()){
int n = in.nextInt();
int m = in.nextInt();
int sum = 0;
while(n-- > 0){
long t = in.nextLong();
sum ^= t%(m+1);
}
if(sum == 0){
System.out.println("Lost");
}else{
System.out.println("Win");
}
}
}
}
以上一些觀點參考於其他的博文,嘿嘿~~~~~,忘大牛勿噴!!!
參考文章:http://blog.163.com/scuqifuguang@126/blog/static/171370086201101711276278/
http://www.cnblogs.com/frog112111/p/3199780.html