组合博弈 SG函数

(给大家安利一部相关电影《美丽心灵~》)

石子游戏

有若干堆石子,每堆石子的数量有限,合法的移动是选择一堆石子并拿走若干颗(不能不拿),如果轮到某个人时所有的石子都被拿完了,则该人失败。
这是一个先手必胜或者必输的组合博弈游戏,具体必胜或是必输取决于石子个数的值

定义

1.无法进行任何合法移动的局面为P-position(即失败局面)
2.可以通过一次合法移动到达P-positon的点为N-position(一次就够了,想赢的人一定会选这个策略的)
3.所有合法移动都到达N-position的点(即没有任何一次合法移动可以移动到P-positon的点)为P-position
通俗的来说,就是当前选手为N-position,他可以经过合法移动到达P-positon从而使下一个选手必败(第三条定义可能有点难理解,可以理解为你已经输了,不断怎么移动对方都会赢,也就是必胜点 )

怎么表示

有向无环图,每个节点是一个局面状态(只能往前走,不能绕回来,有点像隐马尔可夫??)
每个节点函数g(即局面对应的g函数的值)为: g ( x ) = m e x { g ( y ) ∣ y 是 x 的 后 继 ( 即 y 是 x 经 过 有 效 步 骤 可 以 到 达 的 局 面 ) } g(x)=mex\{g(y)|y是x的后继(即y是x经过有效步骤可以到达的局面)\} g(x)=mex{g(y)yx(yx)}(也就是说所有x能到达的局面都放在这个大括号里求一个mex)
对于一个 g ( x ) = 0 g(x)=0 g(x)=0的顶点x,它的所有前驱y都满足 g ( y ) ! = 0 g(y)!=0 g(y)!=0,对于一个 g ( x ) ! = 0 g(x)!=0 g(x)!=0的顶点,必定存在一个后继y满足g(y)=0
g(x)=0就是必败点,!=0代表必胜点
mex函数定义为最小的不属于这个集合的非负整数;
好像有点抽象,还是结合下面的直观理解来看

对于石子游戏,g当且x等于0时才等于0

理解

为了更好的理解上边的定义,举个实例,假如每次必须拿1-3个石子,各个n的g函数的值如下:
在这里插入图片描述
当n=0时,也就是当前选手必败点,就是P;
当n=1、2、3时,当前选手对应拿走1、2、3个便可以直接获胜,所以必胜点N;
当n=4时,当前选手不管拿走1、2、3个,下一个选手都可以通过对应拿走3、2、1个从而获胜,所以是当前选手必败点N;
当n=5时,当前选手不管拿走几个,可能会剩下2、3、4个,下个对手就可以对应拿走1、2、3个从而获胜,所以是当前选手必败点N;

以上是靠主观理解来一个一个算的,当n大时这样不可行,所以引入上文提到的g函数(实际是SG函数)来通过递推得到对应值:
首先可知,n=0是必败点为P;n=1、2、3都可以通过一步操作到达0这个p点,所以都是必胜点;n=4,通过合法移动会变成1、2、3,均是已被标记的为N的点,所以是P点(根据定义第三条)这是递推的思路;
可以证明,SG函数(对于一个g(x)=0的顶点x,它的所有前驱y都满足 g(y)!=0。对于一个g(x)!=0的顶点,必定存在一个后继y满足g(y)=0,g(x)=0就是必败点,!=0代表必胜点)刚好符合上边提到的性质。

异或

进一步扩展为:
有n堆,每一堆分别有a1、a2、…、an个小石子,从A开始,A、B两个人轮流抓,每人每次必须从某一堆石子里面抓1-3个,抓走最后一个石子的人获胜。在双方都尽力不犯错的情况下,问A、B谁能赢?

接下来定义有向图游戏的和,设G1、G2、……、Gn是n个有向图游戏,定义游戏G是G1、G2、……、Gn的和(sum),游戏G的移动规则是:任选一个子游戏Gi并移动上面的棋子。SG函数理论为: g ( G ) = g ( G 1 ) g ( G 2 ) … … g ( G n ) g(G)=g(G1)^g(G2)^……^g(Gn) g(G)=g(G1)g(G2)g(Gn),即游戏的和的SG函数值是它所有子游戏的SG函数值的异或。
参考

题目

Brave Game入门级

在这里插入图片描述

代码

我们其实可以直接用上边1-3个石子的结论,由图表可以观察到,当n=0,4,8,12……时,是必败的,也就是(3+1)的倍数;
所以只要先手能够拿完后留下(m+1)的倍数即可,反过来如果先手时,n为(m+1)的倍数,那么先手必输


int main()
{
    int c;
    scanf("%d",&c);
    while(c--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        if(n%(m+1))
            printf("first\n");
        else
            printf("second\n");
    }
    return 0;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值