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