公平组合游戏
公平组合游戏(Impartial Game)的定义如下:
-
游戏有两个人参与,二者轮流做出决策,双方均知道游戏的完整信息;
-
任意一个游戏者在某一确定状态可以作出的决策集合只与当前的状态有关,而与游戏者无关;
-
游戏中的同一个状态不可能多次抵达,游戏以玩家无法行动为结束,且游戏一定会在有限步后以非平局结束。
非公平组合游戏
非公平组合游戏(Partizan Game)与公平组合游戏的区别在于在非公平组合游戏中,游戏者在某一确定状态可以做出的决策集合与游戏者有关。大部分的棋类游戏都 不是 公平组合游戏,如国际象棋、中国象棋、围棋、五子棋等(因为双方都不能使用对方的棋子)。
反常游戏
反常游戏(Misère Game)按照传统的游戏规则进行游戏,但是其胜者为第一个无法行动的玩家。以 Nim 游戏为例,Nim 游戏中取走最后一颗石子的为胜者,而反常 Nim 游戏中取走最后一刻石子的为败者。
公平组合游戏
经典的公平组合游戏有很多,包括取数游戏,31 点,以及 Nim 游戏等。
博弈图和状态¶
如果将每个状态视为一个节点,再从每个状态向它的后继状态连边,我们就可以得到一个博弈状态图。
例如,如果节点(i,j,k) 表示局面为 i,j,k 时的状态,则我们可以画出下面的博弈图(由于篇幅有限,故仅显示部分状态节点和部分边):
定义 必胜状态 为 先手必胜的状态,必败状态 为 先手必败的状态。
通过推理,我们可以得出下面三条定理:
- 定理 1:没有后继状态的状态是必败状态。
- 定理 2:一个状态是必胜状态当且仅当存在至少一个必败状态为它的后继状态。
- 定理 3:一个状态是必败状态当且仅当它的所有后继状态均为必胜状态。
对于定理 1,如果游戏进行不下去了,那么这个玩家就输掉了游戏。
对于定理 2,如果该状态至少有一个后继状态为必败状态,那么玩家可以通过操作到该必败状态;此时对手的状态为必败状态——对手必定是失败的,而相反地,自己就获得了胜利。
对于定理 3,如果不存在一个后继状态为必败状态,那么无论如何,玩家只能操作到必胜状态;此时对手的状态为必胜状态——对手必定是胜利的,自己就输掉了游戏。
如果博弈图是一个有向无环图,则通过这三个定理,我们可以在绘出博弈图的情况下用O(n+m) 的时间(其中 N为状态种数, M为边数)得出每个状态是必胜状态还是必败状态。
SG函数主要性质 如果x 状态可以到达 状态 y1,y2, ......yn那么 SG(x)=SG(y1)^SG(y2)....^SG(yn) 这里的“ ^ ”是C++中的异或运算。
尽管SG函数的定义十分复杂,但是应用起来却十分容易。
主要分为两步:
1.用记忆化搜索求出x 可能到达的所有状态。
2.递归求解SG函数用hash 表记录所有出现过的状态,找到Mex({x},{y1}........{yn});
注:Mex函数求的是在非负整数中不在集合中出现过的数构成的集合中的最小值。
const int N=110,M=1e4+10;
int s[N],f[M],x;
int sg(int x){
if(f[x]!=-1) return f[x];
unordered_set<int >S;
for(int i=1;i<=k;i++){
int sum=s[i];
if(x>=sum) S.insert(sg(x-sum));
}
for(int i=0;;i++)
if(!S.count(i)) return f[x]=i;
}