目录

预备知识

普通的Nim游戏

SG函数

预备知识

公平组合游戏(ICG)

若一个游戏满足:

  • 由两名玩家交替行动;
  • 游戏中任意时刻,合法操作集合只取决于这个局面本身;
  • 若轮到某位选手时,若该选手无合法操作,则这名选手判负;

则称该游戏为一个公平组合游戏

Nim游戏

有若干堆石子,每堆石子的数量都是有限的,合法的移动是“选择一堆石子并拿走若干颗(不能不拿)”,如果轮到某个人时所有的石子堆都已经被拿空了,则判负(因为他此刻没有任何合法的移动)。

mex(minimal exdudant)函数

设 \(S\) 表示一个非负整数集合。定义 \(mex(S)\) 为求出不属于集合 \(S\) 的最小非负整数的运算。

如:{ \(0,1,3\) } 对应的 \(mex值\) 就是 \(2\) 。

SG函数简介

定义 \(SG(x)=mex(S)\) ,其中 \(S\) 指 \(x\) 的后继状态对应的 \(SG函数值\) 的集合。

在 \(SG\)函数板块对应的模板题中(见下),\(x\) 代表着该堆石子的数量。

普通的Nim游戏

题目传送门:https://www.acwing.com/problem/content/893/

题面:给定n堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。

问如果两人都采用最优策略,先手是否必胜。

分析

这题的结论十分地简洁,就是:

若 \(a_{1} \bigoplus a_{2} \bigoplus a_{3}...\bigoplus a_{n}=0\) ,则先手必负,否则先手必胜。

证明:

我们记 \(a_{1} \bigoplus a_{2} \bigoplus a_{3}...\bigoplus a_{n}\) 为数列a的异或和,以下简记为异或和

先给出两条引理:

  • \(a_{1} \bigoplus a_{2} \bigoplus a_{3}...\bigoplus a_{n}=x~(x>0)\) 时,必可以从一堆石子中拿走若干个石子,使得异或和为 \(0\)。

    证明:\(x\) 的最高位(记为第 \(k\) 位)是 \(1\) ,\(a\) 中必然存在 \(a_i\) 满足 \(a_i\) 第 \(k\) 位是 \(1\) ,那么我们将 \(a_i\) 变为 \(a_i \bigoplus x\) (因为 \(x\not=0\),所以这样操作一定合法),那么变换后的异或和即为 \(0\) 。

  • \(a_{1} \bigoplus a_{2} \bigoplus a_{3}...\bigoplus a_{n}=0\) 时,不存在合法操作,使得异或和仍为 \(0\)。

    证明:假设将 \(a_i\) 变为 \(v\) 后异或和为 \(0\)

    即 \(a_{1} \bigoplus a_{2}... \bigoplus a_{i}...\bigoplus a_{n}=0\) ,我们将这个式子与上式 \(a_{1} \bigoplus a_{2}... \bigoplus v...\bigoplus a_{n}=0\) 联立,即得 \(a_{i}\bigoplus v=0\),意味着 \(a_{i}=v\) ,即 \(a_{i}\) 不变,不是合法操作,故矛盾。

证明完引理后就不难了:

若轮到先手时,异或和为 \(0\) ,那么无论先手如何行动,后手都可以进行操作,使再次轮到先手时异或和仍为 \(0\) ,而游戏结束时异或和必然为 \(0\) ,故先手必败。

反之(即若轮到先手时,异或和不为 \(0\) )后手必败。

代码:
#include<bits/stdc++.h>
using namespace std; int main(){
int n;
cin>>n;
int res=0;
for(int i=1;i<=n;i++){
int k; cin>>k;
res^=k;
}
if(res) puts("Yes");
else puts("No");
return 0;
}

SG函数

利用一道模板题引入:

题目传送门https://www.acwing.com/problem/content/description/895/

题面

给定 \(n\) 堆石子以及一个由 \(k\) 个不同正整数构成的数字集合 \(S\) 。

现在有两位玩家轮流操作,每次操作可以从任意一堆石子中拿取石子,每次拿取的石子数量必须包含于集合 \(S\) ,最后无法进行操作的人视为失败。

问如果两人都采用最优策略,先手是否必胜。

分析

先从一堆石子分析开始:

例如:该堆石子有 \(6\) 个,每次可取 \(2\) 或 \(3\) 个,求 \(SG(6)\) 。

我们可以画出一棵树,代表着两人的决策树。

注意到 \(SG(0)=0\)

根据 \(SG\) 函数的定义,对于决策树上的点对应 \(SG\) 函数值为:

我们还可以自己构造一棵 \(SG\) 函数值构成的树:

从中我们可以直观地看出 \(SG\) 的两个重要性质:

  • 非 \(0\) 结点可以到 \(0\) 结点
  • \(0\) 结点一定不可以到非 \(0\) 结点

根据 \(SG\) 函数的性质以及游戏规则,\(SG(x)=0\) 时意味着相应的玩家必负。

分析多堆石子的情况:

我们规定,对于每堆石子 \(G_i\) ,对应的 \(SG(G_i)=SG(x)\) ,其中 \(x\) 是该堆石子最初的数量

结合这棵树:



从 \(SG\) 函数可以看出,当先手进行决策后,对应的的 \(SG\) 函数值可以为 \([0,SG(x)-1]\),这恰好就像我们最初讨论的普通的Nim问题中取石子的规则!

在这里,我们将 \(SG\) 函数值看成是普通的Nim问题中石子的数量就可以用相同的方法解决了。

求 \(SG\) 函数的办法

我采取的是记忆化搜索的办法,见下:

int f[M]; // SG函数的值
int s[N]; // 可以取多少石子 int sg(int x){
if(f[x]!=-1) return f[x]; // 当已经更新过就直接返回。 unordered_set<int> S;
for(int i=1;i<=k;i++)
if(x-s[i]>=0) S.insert(sg(x-s[i])); for(int i=0;;i++)
if(!S.count(i)) return f[x]=i;
}
代码:
#include<bits/stdc++.h>
using namespace std; const int N=105 ,M=1e4+5;
int n,k;
int f[M]; // SG函数的值
int s[N]; // 可以取多少石子 int sg(int x){
if(f[x]!=-1) return f[x]; // 当已经更新过就直接返回。 unordered_set<int> S;
for(int i=1;i<=k;i++)
if(x-s[i]>=0) S.insert(sg(x-s[i])); for(int i=0;;i++)
if(!S.count(i)) return f[x]=i;
} int main(){
memset(f,-1,sizeof f); // init cin>>k;
for(int i=1;i<=k;i++) cin>>s[i]; cin>>n; int res=0;
for(int i=1;i<=n;i++){
int t; cin>>t;
res^=sg(t);
}
if(res) puts("Yes");
else puts("No"); return 0;
}

【博弈论】组合游戏及SG函数浅析的更多相关文章

  1. HDU 1864 Brave Game 【组合游戏,SG函数】

    简单取石子游戏,SG函数的简单应用. 有时间将Nim和.SG函数总结一下……暂且搁置. #include <cstdio> #include <cstring> #define ...

  2. Nim 游戏、SG 函数、游戏的和

    Nim游戏 Nim游戏定义 Nim游戏是组合游戏(Combinatorial Games)的一种,准确来说,属于“Impartial Combinatorial Games”(以下简称ICG).满足以 ...

  3. uoj266[清华集训2016]Alice和Bob又在玩游戏(SG函数)

    uoj266[清华集训2016]Alice和Bob又在玩游戏(SG函数) uoj 题解时间 考虑如何求出每棵树(子树)的 $ SG $ . 众所周知一个状态的 $ SG $ 是其后继的 $ mex $ ...

  4. Nim游戏与SG函数 ——博弈论小结

    写这篇博客之前,花了许久时间来搞这个SG函数,倒是各路大神的论文看的多,却到底没几个看懂的.还好网上一些大牛博客还是性价比相当高的,多少理解了些,也自己通过做一些题加深了下了解. 既然是博弈,经典的N ...

  5. [您有新的未分配科技点]博弈论入门:被博弈论支配的恐惧(Nim游戏,SG函数)

    今天初步学习了一下博弈论……感觉真的是好精妙啊……希望这篇博客可以帮助到和我一样刚学习博弈论的同学们. 博弈论,又被称为对策论,被用于考虑游戏中个体的预测行为和实际行为,并研究他们的应用策略.(其实这 ...

  6. 博弈论(nim游戏,SG函数)

    说到自己,就是个笑话.思考问题从不清晰,sg函数的问题证明方法就在眼前可却要弃掉.不过自己理解的也并不透彻,做题也不太行.耳边时不时会想起alf的:"行不行!" 基本的小概念 这里 ...

  7. bzoj 1188 [HNOI2007]分裂游戏(SG函数,博弈)

    1188: [HNOI2007]分裂游戏 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 733  Solved: 451[Submit][Status ...

  8. 数学:Nim游戏和SG函数

    有若干堆石子,两人轮流从中取石子,取走最后一个石子的人为胜利者 以下的性质是显然的 .无法移动的状态是必败态 .可以移动到必败态的局面一定是非必败态 .在必败态做所有操作的结果都是非必败态 在普通Ni ...

  9. 【BZOJ1874】取石子游戏(SG函数)

    题意:小H和小Z正在玩一个取石子游戏. 取石子游戏的规则是这样的,每个人每次可以从一堆石子中取出若干个石子, 每次取石子的个数有限制,谁不能取石子时就会输掉游戏. 小H先进行操作, 他想问你他是否有必 ...

随机推荐

  1. Watch the Wifi: Visually Stunning Look at the Digital World Invading Cities (video)

    http://singularityhub.com/2011/04/01/watch-the-wifi-visually-stunning-look-at-the-digital-world-inva ...

  2. Lua 从入门到放弃

    Lua 从入门到放弃 What is Lua? Lua is a powerful, efficient, lightweight, embeddable scripting language. It ...

  3. 如何在Python 中使用UTF-8 编码 && Python 使用 注释,Python ,UTF-8 编码 , Python 注释

    如何在Python 中使用UTF-8 编码 && Python 使用 注释,Python ,UTF-8 编码 , Python  注释 PIP $ pip install beauti ...

  4. ORM All In One

    ORM All In One ORM Object Relational Mapping https://en.wikipedia.org/wiki/Object-relational_mapping ...

  5. PM2 in depth

    PM2 in depth ecosystem.config.js module.exports = { apps : [{ name: "app", script: ". ...

  6. Python学习笔记_生成验证码

    import random def verification_code(): num = [str(x) for x in range(10)] # 列表生成器0-9 upper = [chr(x) ...

  7. 使用python编写量子线路打印的简单项目,并使用Sphinx自动化生成API文档

    技术背景 该文章一方面从量子线路的打印着手,介绍了一个简单的python量子线路工程.同时基于这个简单的小工程,我们顺带的介绍了python的API文档自动化生成工具Sphinx的基本使用方法. 量子 ...

  8. ConcurrentHashMap允许一边遍历一边更新,而用HashMap则会报线程安全问题

    ConcurrentHashMap线程安全的,允许一边更新.一边遍历,也就是说在对象遍历的时候,也可以进行remove,put操作,且遍历的数据会随着remove,put操作产出变化,而如果用Hash ...

  9. jenkins+docker+nginx+tomcat实现vue项目部署

    一.项目准备 1.新建一个vue的项目,确保能在浏览器正常访问.然后在项目的根目录下新建一个Dockerfile的文件,内容如下 FROM nginx COPY dist /usr/share/ngi ...

  10. @Transaction注解失效的几种场景

    一.@Transactional介绍 1.@Transactional注解可以作用于哪些地方? @Transactional 可以作用在接口.类.类方法上. 作用于类:表示所有该类的public方法都 ...