目录

预备知识

普通的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. 三、mysql主从复制

    1 MySQL 主从复制 1.1 主从复制的含义 在 MySQL 多服务器的架构中,至少要有一个主节点(master),跟主节点相对的,我们把它叫做从节点(slave). 主从复制,就是把主节点的数据 ...

  2. 深入理解JavaScript中的类继承

    由于写本文时全部是在编辑器中边写代码边写感想的,所以,全部思想都写在代码注释里面了 // 类继承 //todo.1 extends 关键字 class Animal { constructor(nam ...

  3. popstate 事件 & history API

    popstate 事件 & history API URL change 当用户浏览会话历史记录时,活动历史记录条目发生更改时,将触发 Window 界面的 popstate 事件. 它将当前 ...

  4. CSS 定位 relative && absolute 问题?

    1 1 1 CSS 定位 relative && absolute 问题? 谁能解释一下,为什么div使用 relative是设置right,bottom 后,看不到div 呀,哪里多 ...

  5. React.memo All In One

    React.memo All In One https://reactjs.org/docs/react-api.html#components React.memo const MyComponen ...

  6. Python Coding Interview

    Python Coding Interview Python Advanced Use enumerate() to iterate over both indices and values Debu ...

  7. auto skip function args

    auto skip function args https://repl.it/@xgqfrms/auto-skip-function-args "use strict"; /** ...

  8. Google can't be accessed again, today is shit day

    Google can't be accessed again, today is shit day 2019.11.28 12:00~20:56 holy shit (pile of poop) Go ...

  9. bowser checker & UA

    bowser checker & UA navigator.userAgent; https://developer.mozilla.org/en-US/docs/Web/HTTP/Brows ...

  10. 验证销售部门的数据查看权限-脚本demo

    1 # coding:utf-8 2 ''' 3 @file: run_old.py 4 @author: jingsheng hong 5 @ide: PyCharm 6 @createTime: ...