学习笔记 SG函数

SG函数

Nim游戏

n堆石子 \(a_1\ \ a_2\ \ a_3\ \ a_4\ \ ......\ \ a_n\)

规则(......)

\(a_1\ \ xor\ \ a_2\ \ xor\ \ a_3\ \ xor\ \ a_4\ \ xor\ \ ......\ \ xor\ \ a_n==0\) ? 后手胜 : 先手胜

太简单了? ? ? hhh

上升一下规则

1.每一次可以从第1堆石子取出1或者2或者3颗

2.每一次可以从第2堆石子取出奇数颗

3.每一次可以从第3堆以及后面取出任意颗

求必胜策略

(一脸懵逼......)


不多说了 正式开始

首先我们定义一个DAG

一个入度为零的点作为起点

起点上有一个棋子 先后手沿有向边轮流移动 无法移动者lose

这就基本上把博弈论转换为了抽象模型 ---> 图论 ? ? ?

SG就是在这个DAG上面定义然后&^$@!&#%......


(1)\(mex\)运算

这是一个基于集合的运算

表示 最小 的不属于该集合的 非负整数

例如 \(mex\{0,1,3,5,6,8,9\}=2\)


(2)定义

当前SG函数如下 : \(SG(x)=mex\{SG(y)|y是x的后继\}\)

......只有定义是没有用的

①所有出度为零的点x(我们简称为汇点) \(SG(x)=0\)

\(SG(x)=0\) 该节点是必败点


必败态:

对于当前状态 TA的后继状态 全部 都是必胜态 那么TA就是必败态

当前状态 无法移动也就是没有后继状态 那么TA就是必败态


如果当前点是一个汇点的话 根据定义 必败无疑

但是如果不是呢 ? ? ?

根据\(mex\)的定义 该节点的后继节点当中所有后继节点 \(SG!=0\)

\(SG(x)!=0\) 该节点对应状态是必胜状态

那么后继节点中一定存在\(SG=0\)的节点

又回到上面那个\(SG(x)=0\)的问题了

这样会一直递归到x是一个汇点

\(SG(x)=0\) 那么\(TA\)的前驱节点\(SG!=0\) 且是必胜态 那么应该就可以理解了


必胜态:

对于当前状态 TA的后继状态 至少有一个 是必败态 那么TA就是必胜态

必败态:

(1)对于当前状态 TA的后继状态 全部 都是必胜态 那么TA就是必败态

(2)当前状态 无法移动也就是没有后继状态 那么TA就是必败态


\(SG(x)=0\) 对应TA是汇点 或者后继结点\(min\{SG(y)|x\ \ can\ \ go\ \ to\ \ y\}>0\)

恰好对应必败态定义

\(SG(x)!=0\) 对应TA的后继结点 \(0∈\{SG(y)|x\ \ can\ \ go\ \ to\ \ y\}\)

恰好对应必胜态定义

(3)实战

说了定义还是一脸蒙蔽 所以 手玩一下? ? ?

①普通Nim游戏(请使用SG()求解)

n堆石子 \(a_1\ \ a_2\ \ a_3\ \ a_4\ \ ......\ \ a_n\)

对于任意一堆石子\(a_i(1<=i<=n)\)

我们可以取\([1,a_i]\)颗 那么剩余石子的范围就是\([0,a-i-1]\)

\(SG(i)=a_i\)

等一下 我们相当于是把每一个石子堆看成了一个游戏

但是怎么合并呢? ? ?

直接上定理:\(SG_{tot}=SG(1)\ \ xor \ \ SG(2)\ \ xor \ \ SG(3)\ \ xor \ \ SG(4)\ \ xor \ \ ......\ \ xor \ \ SG(n)\)

也就是游戏的SG值就是子游戏的SG值得异或和

然后\(SG_{tot}=0\) 对应必败态 恰好石子堆的异或和为0 就是后手必胜

是不是有些眉目了 ? ? ?

SG定理的证明:【https://www.zhihu.com/question/51290443/answer/125105697】

因为我太菜鸡所以当然不会证明辣

②文艺Nim游戏(请使用SG()求解)

每一次可以从第1堆石子取出1或者2或者3颗

每一次可以从第2堆石子取出奇数颗

每一次可以从第3堆以及后面取出任意颗

其余不变

用SG求解

先埋一个局。。。。。。

SG模板

normal

void calc_SG(int x)
{
    for(i ...枚举所有后继状态)
    vis[SG[i]]=1;
}

memset(vis,0,sizeof vis);
calc_SG(x);
for(int i=0;;++i) if(!vis[i]) {SG[x]=i;break;}

时间戳优化 (卡常小技巧)

//memset(vis,0,sizeof vis) 会被卡常 所以我们尝试优化

void calc_SG(int x)
{
    for(i ...枚举所有后继状态)
    vis[SG[i]]=tot;
}

++tot;
calc_SG(x);
for(int i=0;;++i) if(vis[i]!=tot) {SG[x]=i;break;}

例题

【HDU1847】

【HDU1848】

我来解上面的局

对于第一种情况 这就是巴什博奕 \(SG[x]=mex\{SG[x-3],SG[x-2],SG[x-1]\}\)

参考博弈树打表也是可以理解的 通式就是\(SG[x]=x%4\)

那么对于第二种情况\(SG[x]=x%2\)

也就是\(SG[x]=mex\{SG[x-1],SG[x-3],......,SG[(x+1)\%2]\}\)

根据博弈树打表也可以理解

第三种情况就是\(Nim\)游戏 可以选择一个一个\(SG\)异或 也可以直接计算\(SG3\)

最终的\(SG_{tot}=SG_1 \bigoplus SG_2 \bigoplus SG_3\)

具体的见例题吧 cdy:别诶

posted @ 2020-10-01 15:12  tcswuzb  阅读(309)  评论(0编辑  收藏  举报