此文为以下博客做的摘要:

https://blog.csdn.net/strangedbly/article/details/51137432

----------------------------------------------------------------------------------------

1、定义P-position和N-positon

P表示Previous,N表示Next。

即上一个移动的人有必胜策略的局面是P-position,“先手必败”或“后手必胜”,现在移动的人有必胜策略的局面是N-positon,“后手必败”或“先手必胜”。下面为更严谨的定义:

1、无法进行任何移动的局面(即terminal position)是P-position;

2、可以移动到P-position的局面是N-position;

3、所有移动都导致N-position的局面是P-position。

根据定义,不重现局面,那么positions的集合可以进行拓扑排序,并且能通过定义判断为P-position还是N-position。

2、Nim游戏

对于一个Nim游戏的局面(a1, a2, ...an),它是P-position当且仅当 a1^a2^...^an = 0,其中 ^ 表示异或运算。

要证明这个定理,基本上是证明这种运算符合上述position的定义。即证明三个命题:1、这个判断将所有无法移动的局面判为P-position;2、被判为N-position的局面一定可以移动到某个P-position;3、被判为P-position的局面无法移动到某个P-position。

第一个命题:无法移动的局面只有全为0,即异或仍为0。

第二个命题:对于某个局面(a1,a2,...,an),若a1^a2^...^an!=0,一定存在某个合法的移动,将ai改变成ai'后满足a1^a2^...^ai'^...^an=0。不妨设a1^a2^...^an=k,则一定存在某个ai,它的二进制表示在k的最高位上是1(否则k的最高位那个1是怎么得到的)。这时ai^k<ai一定成立。则我们可以将ai改变成ai'=ai^k,此时a1^a2^...^ai'^...^an=a1^a2^...^an^k=0。

第三个命题:对于某个局面(a1,a2,...,an),若a1^a2^...^an=0,一定不存在某个合法的移动,将ai改变成ai'后满足a1^a2^...^ai'^...^an=0。因为异或运算满足消去率,由a1^a2^...^an=a1^a2^...^ai'^...^an可以得到ai=ai'。所以将ai改变成ai'不是一个合法的移动。证毕。

3、Sprague-Grundy函数

首先给出这个函数适用范围,貌似所有博弈的题目都是符合这个范围。现在来研究似乎更为一般的游戏:给定一个有向无环图和一个其实顶点上的一枚棋子,两名选手交替将这棋子沿有向边移动,无法移动者判负。事实上,这个游戏可以认为是所有Impartial Combinatorial Games的抽象模型。即任何一个ICG都可以通过把每个局面看成一个顶点,对每个局面和它的子局面连一条有向边来抽象成这个“有向图游戏”。

首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。

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

来看一下SG函数的性质。首先,所有的terminal position所对应的顶点,也就是没有出边的顶点,其SG值为0,因为它的后继集合是空集。下面为原作图

(pic1)

对于一个g(x) = 0的顶点x,它的所有后继 y 都满足 g(y) != 0。

对于一个g(x) != 0的顶点,必定存在一个后继 y 满足 g(y) = 0。

即顶点 x 代表的position为P-position,当且仅当 g(x) = 0。相应地N-position为 g(x) != 0。所以有向无环图的每个顶点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枚棋子的必胜策略!

对于n个棋子,设它们对应的顶点的SG值分别为(a1,a2,...,an),再设局面(a1,a2,...,an)时的Nim游戏的一种必胜策略是把ai变成k,那么原游戏的一种必胜策略就是把第i枚棋子移动到一个SG值为k的顶点。其实我们还是只要证明这种多棋子的有向图游戏的局面是P-position当且仅当所有棋子所在的位置的SG函数的异或为0。这个证明与上面的Bouton's Theorem几乎是完全相同的,只需要适当的改几个名词就行了。

刚才,为了使问题看上去更容易一些,认为n枚棋子是在一个有向图上移动。但如果不是在一个有向图上,而是每个棋子在其对应的有向图上,每次可以任选一个棋子(也就是任选一个有向图)进行移动,这样也不会给结论带来任何变化。

所以我们可以定义有向图游戏的和(Sum of Graph Games):设G1、G2、……、Gn是n个有向图游戏,定义游戏G是G1、G2、……、Gn的和(Sum),游戏G的移动规则是:任选一个子游戏Gi并移动上面的棋子。Sprague-Grundy Theorem就是:g(G)=g(G1)^g(G2)^...^g(Gn)。也就是说,游戏的和的SG函数值是它的所有子游戏的SG函数值的异或。

任何一个ICG都可以抽象成一个有向图游戏。所以“SG函数”和“游戏的和”的概念就不是局限于有向图游戏。我们给每个ICG的每个position定义SG值,也可以定义n个ICG的和。所以说当我们面对由n个游戏组合成的一个游戏时,只需对于每个游戏找出求它的每个局面的SG值的方法,就可以把这些SG值全部看成Nim的石子堆,然后依照找Nim的必胜策略的方法来找这个游戏的必胜策略了!(Nim其实就是n个从一堆中拿石子的游戏求SG的变型,总SG=n个sg的异或)。(very important)

有n堆石子,每次可以从第1堆石子里取1颗、2颗或3颗,可以从第2堆石子里取奇数颗,可以从第3堆及以后石子里取任意颗……我们可以把它看作3个子游戏,第1个子游戏只有一堆石子,每次可以取1、2、3颗,很容易(看下图pic2)看出x%4==0时处于P局面,即x颗石子的局面的SG值是x%4,(即把pic2中的值改成原值%4)。第2个子游戏也是只有一堆石子,每次可以取奇数颗,经过简单的画图可以知道这个游戏有x颗石子时的SG值是x%2。第3个游戏有n-2堆石子,就是一个Nim游戏。对于原游戏的每个局面,把三个子游戏的SG值异或一下就得到了整个游戏的SG值,然后就可以根据这个SG值判断是否有必胜策略以及做出决策了。其实看作3个子游戏还是保守了些,干脆看作n个子游戏,其中第1、2个子游戏如上所述,第3个及以后的子游戏都是“1堆石子,每次取几颗都可以”,称为“任取石子游戏”,这个超简单的游戏有x颗石子的SG值显然就是x。其实,n堆石子的Nim游戏本身不就是n个“任取石子游戏”的和吗?

(pic2)

所以,对于我们来说,SG函数与“游戏的和”的概念不是让我们去组合、制造稀奇古怪的游戏,而是把遇到的看上去有些复杂的游戏试图分成若干个子游戏,对于每个比原游戏简化很多的子游戏找出它的SG函数,然后全部异或起来就得到了原游戏的SG函数,就可以解决原游戏了。

以下是本文最重要的部分:

解题模型:

1.把原游戏分解成多个独立的子游戏,则原游戏的SG函数值是它的所有子游戏的SG函数值的异或。

       sg(G)=sg(G1)^sg(G2)^...^sg(Gn)。

2.分别考虑没一个子游戏,计算其SG值。

SG值的计算方法:(重点

1.可选步数为1~m的连续整数,直接取模即可,SG(x) = x % (m+1);

2.可选步数为任意步,SG(x) = x;

3.可选步数为一系列不连续的数,用模板计算。

  模板1:打表

 //f[], 可以取走的石头个数
//sg[],SG函数值
//mex[],mex{}
int f[MAXN], sg[MAXN], mex[MAXN];
void getSG(int n)
{
int i, j;
memset(sg, , sizeof(sg));
for(i = ;i <= n;++i)
{
memset(mex, , sizeof(mex));
for(j = ;f[j] <= i;++j)
mex[sg[i - f[j]] = ;
for(j = ;j <= n;++j)
if(mex[j] == )
{
sg[i] = j;
break;
}
}
}

  模板2:DFS

//s[i] 数组要从小排到大,SG函数要初始化为 -1, 每个集合只需初始化一遍
//n是集合s 的大小,s[i]是定义的特殊取法规则的数组
int s[], sg[], n;
//memset(sg, -1, sizeof(sg));
//sort(s, s + n);
int SG_dfs(int x)
{
int i;
if(sg[x] != -)
return sg[x];
bool vis[];
memset(vis, , sizeof(vis));
for(i = ;i < n;++i)
{
if(x >= s[i])
{
SG_dfs(x - s[i]);
vis[sg[x - s[i]] = ;//mex{}
}
}
int e;
for(i = ;;++i)
if(!vis[i])
{
e = i;
break;
}
return sg[x] = e;
}

  首选打表,实在不行才用DFS。

3.计算sg(G)=sg(G1)^sg(G2)^...^sg(Gn),sg(G)=0,即P-Position,即先手必败。

--------------------------------------------------------------------------------------------

原博主下面还有题,另外也开了一篇写题的博客

(转)博弈 SG函数的更多相关文章

  1. S-Nim HDU 1536 博弈 sg函数

    S-Nim HDU 1536 博弈 sg函数 题意 首先输入K,表示一个集合的大小,之后输入集合,表示对于这对石子只能去这个集合中的元素的个数,之后输入 一个m表示接下来对于这个集合要进行m次询问,之 ...

  2. hdu 3032(博弈sg函数)

    题意:与原来基本的尼姆博弈不同的是,可以将一堆石子分成两堆石子也算一步操作,其它的都是一样的. 分析:由于石子的堆数和每一堆石子的数量都很大,所以肯定不能用搜索去求sg函数,现在我们只能通过找规律的办 ...

  3. HDU-4678 Mine 博弈SG函数

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4678 题意就不说了,太长了... 这个应该算简单博弈吧.先求联通分量,把空白区域边上的数字个数全部求出 ...

  4. 尼姆博弈+SG函数

    博弈这个东西真的很费脑诶.. 尼姆博奕(Nim Game):游戏者轮流从一堆棋子(或者任何道具)中取走一个或者多个,最后不能再取的就是输家.当指定相应数量时,一堆这样的棋子称作一个尼姆堆 当n堆棋子的 ...

  5. 【转】博弈—SG函数

    转自:http://chensmiles.blog.163.com/blog/static/12146399120104644141326/ http://blog.csdn.net/xiaofeng ...

  6. HDU 1848 Fibonacci again and again (斐波那契博弈SG函数)

    Fibonacci again and again Time Limit: 1000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & ...

  7. Light OJ 1199 - Partitioning Game (博弈sg函数)

    D - Partitioning Game Time Limit:4000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu ...

  8. LightOJ 1315 - Game of Hyper Knights(博弈sg函数)

    G - Game of Hyper Knights Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%lld & ...

  9. Light OJ 1296 - Again Stone Game (博弈sg函数递推)

    F - Again Stone Game Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu ...

随机推荐

  1. p2150 [NOI2015]寿司晚宴

    传送门 分析 我们发现对于大于$\sqrt(n)$的数每个数最多只会包含一个 所以我们把每个数按照大质数的大小从小到大排序 我们知道对于一种大质数只能被同一个人取 所以f1表示被A取,f2表示被B取 ...

  2. Luogu 3537 [POI2012]SZA-Cloakroom

    背包. 首先考虑将所有询问离线按照$m$从小到大排序,然后把所有物品按照$a$从小到大排序,对于每一个询问不断加入物品. 设$f_i$表示在组成容量为$i$的背包的所有方案中$b$最小的一个物品的最大 ...

  3. Python基础-3

    目录 1. 函数基本语法及特性 2. 参数与局部变量 3. 返回值 知识插入:嵌套函数 4.递归 5.匿名函数 6.函数式编程介绍 7.高阶函数 8.内置函数 一.函数基本语法 函数是什么? 函数一词 ...

  4. App测试从入门到精通之兼容性和回归测试

    兼容性测试需要考虑的APP测试点 1.不同网络环境下的兼容性测试 2.不同手机操作系统兼容性测试 3.不同应用软件的兼容性测试 4.不同的容量大小的SIM卡之间的互相兼容测试 5.当安装杀毒软件时,应 ...

  5. DELPHI XE5 UP2 运行IOS 遇到 Wrapper init failed: (null)问题的解决办法

    一.问题表现: 在MAC OSX(10.9.2)上安装了比较新的XCODE5.1 和COMMAND LINE TOOLS 在DELPHI XE5 UP2上放了一个按钮,输出到MAC OSX上,出现: ...

  6. $(this)在ajax里面不生效的探究

    第一个箭头时, 如果没有将$(this) 赋值给 _this ,那么$(this)就无法在ajax方法里面使用. 应该是应为他们属于不同的域. 赋值给_this的话, 就类似于全局变量

  7. 「BZOJ 2152」聪聪可可

    题目链接 戳这 \(Solution\) 这道题看起来就像点分治对吧.没错就是点分治. 什么是点分治 如果你不会点分治,可以去看看这儿 现在看到这里,首先确保你已经会了点分治,如果不会你还往下看,听不 ...

  8. List_Delete

    /*Sorting from little to large use List*/ #include <stdio.h> /* printf, scanf, NULL */ #includ ...

  9. kali linux之手动漏洞挖掘二

    漏洞挖掘原则/宗旨----所有变量,所有头(cookie中的变量),逐个变量删除 身份认证 常用若口令/基于字典的密码爆破/锁定帐号 信息收集(手机号,身份证,住址信息等等) 密码嗅探 会话sessi ...

  10. 入参为json类型的接口测试示例

    一.接口文档内容 二.使用postman(入参为json类型) 如下部分内容即是json串: { "name":"刘星", "grade": ...