我的理解: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函数 } }
来一道裸题