昨天考了个博弈论题,发现自己SG函数什么的全忘了,于是重学一遍
前置知识
必胜点和必败点
◦ P点:必败,换而言之就是谁处于此位置则在双方操作正确的情况下必败。
◦ N点:必胜,处于此情况下双方操作均正确的情况下必胜。
性质
1.所有终结点是必败点P。
2.从任何必胜点N操作, 至少有一种方式可以进入必败点 P。
3.无论如何操作,必败点P都只能进入必胜点 N。
以$Nim$游戏为例。nim游戏的规则是这样的:地上有n堆石子,每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取完,不能不取。每次只能从一堆里取。最后没石子可取的人就输了。假如甲是先手,且告诉你这n堆石子的数量,他想知道是否存在先手必胜的策略。
通过打表等方法...可以发现,对于一个 nim 游戏的局面 ?1,?2,…,??,它是 P点当且仅当?1⨁?2⨁…⨁??=0
暂时不需要知道是怎么算出来的,只要它符合上面的三条性质,就可以证明正确:
1. 终结点只有一种,就是 0,0,…,0,显然符合异或后为 0,为 P点。
2. 对于 ?1,?2,…,??且?1⨁?2⨁…⨁??=0,经一次移动后必然到达 ?1,?2,…,??,其中?1⨁?2⨁…⨁??≠0,从而到达 N点。
3. 对于 ?1,?2,…,??且?1⨁?2⨁…⨁??≠0,必存在移动方法可以到达P点。
nim游戏属于公平组合游戏(Impartial Combinatorial Games)。它的规则如下:
1.有两名选手;
2.两名选手交替对游戏进行移动,每次一步,选手可以在有限的合法移动集合中任选一种进行移动;
3.合法的移动集合只取决于这个局面本身,不取决于轮到哪名选手操作、以前的任何操作等因素;
4.如果轮到某名选手移动,且这个局面的合法的移动集合为空(也就是说此时无法进行移动),则这名选手负。
有向图移动游戏可以看作所有ICG的抽象模型。也就是说,所有ICG游戏都可以看成:
给定一个 DAG 及一个点上的棋子,两名选手交替将沿边移动,无法移动判负。
我们把 NIM 游戏的每一个状态看成点,把这和其可以转移到下连边,那么 NIM 游戏也被抽象成了一个有向图移动游戏。
$Sprague-Garundy$函数
定义$mex$(minimal excludant)运算.这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。例如$mex${0,1,2,4}=3、$mex${2,3,5}=0、$mex${}=0。
对于一个给定的有向无环图,定义关于图的每个顶点的$SG$函数如下:sg(x)=mex{ sg(y) | y是x的后继 }。
首先,所有终结点的SG=0,因为它没有后继节点。
对于一个g(x)= 0的顶点P,它的所有后继y都满足g(y)≠0。
对于一个g(x)≠0的顶点N,必定存在一个后继y满足g(y)= 0。
那么可以发现,顶点为P的充要条件为g(顶点)= 0,这时对于这个游戏有必胜策略。
回到nim游戏,如果把每一堆石子都看作一个DAG,用分治的思想考虑,有必胜策略的条件就是g(G) = g(G1)^g(G2)^...^g(Gn) = 0。
步骤
- 把原游戏分解成多个独立的子游戏,则原游戏的SG函数值是它的所有子游戏的SG函数值的异或。
- 分别考虑每一个子游戏,计算其SG值。
- 可选步数为1~m的连续整数,直接取模即可,SG(x) = x % (m+1);
- 可选步数为任意步,SG(x) = x;
- 可选步数为一系列不连续的数,打表
- sg(G)=sg(G1)^sg(G2)^...^sg(Gn)。
#include<iostream> #include<cstdio> #include<cstring> #define MogeKo qwq using namespace std; int t,n,k,ans; int main(){ scanf("%d",&t); while(t--){ scanf("%d",&n); ans = 0; for(int i = 1;i <= n;i++){ scanf("%d",&k); ans ^= k; } if(ans)printf("Yes\n"); else printf("No\n"); } return 0; }