sg函数 和 博弈

这几天一直在看博弈,一直想写博客,但又一直没写,感觉自己没有搞懂sg函数,几种简单的博弈似乎是看懂了。。。但是sg函数到现在我还是在用着,但是我有些疑惑并不懂。

首先先贴一下几个博客,
第一就是kuangbin菊苣的博客了:
这是他转的:http://www.cnblogs.com/kuangbin/archive/2011/08/28/2156426.html
这是他的一些题目:http://www.cnblogs.com/kuangbin/category/319084.html

这个上面的题我都刷了一遍,感觉是难度有点低
http://blog.sina.com.cn/s/blog_83d1d5c70100y9yd.html

首先保证至少第一个链接里面的东西必须要完全理解才算入门吧

博弈部分,上面的第一个链接讲的很详细

hdu

1846 : 简单的bash博弈,简单做

2147:

一个棋子在右上角,先要将其移到左下角,可以向左、下、左下方移动,依次博弈,可以发现也是一个bash博弈,时间复杂度够扫一遍,即可。

2188:同理bash博弈
2149:

bash博弈,不过比最简单的稍微复杂了一丢丢

1847 :

bash博弈的变形,把能取牌的方式变成了2的幂次。2的指数增长很快,所以我们打表然后扫一下就好了

1850:

nim博弈,求有多少种取法:
首先异或和不为0才能赢, 然后我们遍历一下所有的堆:(其他堆异或和= sum^这一堆的数量) 我们在每一堆中取完后异或和都必须为0。所以统计一下每一堆是否可取就可以了。

**1848 :

nim博弈变形,能取的石头数量变成了斐波那契数,我们把每一堆的sg函数跑出来,然后异或起来就可以了,至于为什么可以这样,我们在下面的sg函数解释

1849 :

nim 博弈变形,我们只需要把每一颗棋子看成一堆石子,然后剩下的聪明的你应该就会了吧。

1517:

p=1,每次可以*2~9 , 先把p乘到>=n的人就赢了。这个问题由于n每次给的都不一样,所以我们并不是很好预处理,不妨每次dfs 一遍即可,2的指数增长是很快的。
sg[i]!=0 的条件是 在 j=i*2~*9里面必须有一个sg[j]=0,否则sg[i]=1.
* 如果我们转换一下
* 有一堆石子 n 个
* 每次只能取 上一次取得石子的2~9 倍, 如果石子不够就全部取走
* 取走最后一颗石子的玩家算赢
* 相当于 bash博弈

1536

nim博弈变形,其实和1848是一样的
题意:
先输入k,代表集合S中有k个数,然后输入k个数。
有m轮回合,每一轮回合先输入m表示有m堆石子,然后每一堆石子有多少个石子数,然后取法只能取S中的数字
但是这里有一个要注意的地方
在用来mex的函数(比如用flag),一定要设置成bool,这样能够让时间快上很多很多。用int可能会T

总结一下,两个要点:
1.当时间空间不够的时候不妨打表找找规律
2.BOOL 类型 就是比int 不知道快到哪里去了

sg函数

给定一个有向无环图和一个起始顶点上的一枚棋子,两名选手交替的将这枚棋子沿有向边进行移动,无法移 动者判负。事实上,这个游戏可以认为是所有Impartial Combinatorial Games的抽象模型。 即ICG问题

也就是说,任何一个ICG都可以通过把每个局面看成一个顶点,对每个局面和它的子局面连一条有向边来抽象成这个“有向图游戏”。下 面我们就在有向无环图的顶点上定义Sprague-Grundy函数。

首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。
这一部分,我到现在也没完全理解为什么要这么做!,先继续看 可以跳过我的猜想,先说下我的猜想:猜想是把这种状态看成一堆石子,sg[i]只是代表i这堆石子有sg[i]个石头,因为剩下的0<=j< i 的石头数我们都能够取到,正好符合下面所说的理念,也符合nim博弈

对于一个给定的有向无环图,定义关于图的每个顶点的Sprague-Grundy函数sg如下:sg(x)=mex{ sg(y) | y是x的后继 }。

来看一下SG函数的性质。
1.首先,所有的terminal position所对应的顶点,也就是没有出边的顶点,其SG值为0,因为它的后继集合是空集。
2.然后对于一个g(x)=0的顶点x,它的所有前驱y都满足 g(y)!=0。
3.对于一个g(x)!=0的顶点,必定存在一个后继y满足g(y)=0。

以上这三句话表明,顶点x所代表的postion是P-position当且仅当sg(x)=0(跟P-positioin/N-position的 定义的那三句话是完全对应的) 也就是说我们可以根据来sg函数的值来判断胜负手
我们通过计算有向无环图的每个顶点的SG值,就可以对每种局面找到必胜策略了。但SG函数的用途远没有这样简单。如果将有 向图游戏变复杂一点,比如说,有向图上并不是只有一枚棋子,而是有n枚棋子,每次可以任选一颗进行移动,这时,怎样找到必胜策略呢?

让我们再来考虑一下顶点的SG值的意义。当g(x)=k时,表明对于任意一个0<=i< k,都存在x的一个后继y满足g(y)=i。也 就是说,当某枚棋子的SG值是k时,我们可以把它变成0、变成1、……、变成k-1,但绝对不能保持k不变。不知道你能不能根据这个联想到Nim游戏, Nim游戏的规则就是:每次选择一堆数量为k的石子,可以把它变成0、变成1、……、变成k-1,但绝对不能保持k不变。这表明,如果将n枚棋子所在的顶 点的SG值看作n堆相应数量的石子,那么这个Nim游戏的每个必胜策略都对应于原来这n枚棋子的必胜策略!
这段话很重要,耐心多看几遍!有不理解的地方再读几遍,这些肯定都是对的。

其实我们还是只要证明这种多棋子的有向图游戏的局面是P-position当且仅当所有棋子所在的位置的SG函数的异或为0。这个证明与上节的Bouton’s Theorem几乎是完全相同的,只需要适当的改几个名词就行了。
刚才,我为了使问题看上去更容易一些,认为n枚棋子是在一个有向图上移动。但如果不是在一个有向图上,而是每个棋子在一个有向图上,每次可以任选一个棋子(也就是任选一个有向图)进行移动,这样也不会给结论带来任何变化。

如此一来就可以解释 上面的两道题,也可以解释为什么sg函数可以喝nim博弈相交互着使用。

最后再看我们上一篇文章里面的博弈吧。

Bomb Game
sg函数的博弈。。。说有一个n,m大小的棋盘,每个炸弹引爆之后可以往左边和上方 分裂两个炸弹,除非它位于最左方或者最上方就不能够分裂。。。 当两个炸弹位于同一个位置时,他们会爆炸,不分裂。 或者(1,1)这个位置永远不会存在炸弹。。。 john先手,问输赢关系。

所以我们可以知道mp[0][0]这一点的sg值肯定是0;
然后第一行和第一列的sg值都是i(j),可以看成一堆石子任意取。
然后对于矩形中的 mp[i][j],这个石子的sg怎么求呢? 首先他左边和上方的所有点sg值都必须已知,如果把它看成一堆石子,他可以分成的两个炸弹就相当于很多后继,我们就找到mex即相当于这一堆石子的数量,然后我们把所有炸弹(即一共的石子堆按nim博弈异或起来即可)

int getsg(int a,int b){  
    int i,j;  
    memset(mp,0,sizeof(mp));  
    for(i=0;i<a;i++)  
        for(j=0;j<b;j++){  
            mp[pri[a][j]^pri[i][b]]=1;  
        }  
    for(i=0;;i++){  
        if(!mp[i])  
        return i;  
    }  
}  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值