公平组合游戏ICG

定义

若一个游戏满足:

  • 由两名玩家交替行动
  • 在游戏进程的任意时刻,可以执行的合法行动与轮到哪名玩家无关
  • 不能行动的玩家判负

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

Nim博弈属于公平组合游戏,但是城建的棋类游戏,比如围棋,就不是公平组合游戏。因为围棋交战双方分别只能落黑子和白子。胜负判定也比较复杂,不满足条件2和条件3。


例题举例1:AcWing 891.Nim游戏

给定n堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。

例如:有两堆石子,第一堆有2个,第二堆有3个,先手必胜。

操作步骤:

  1. 先手从第二堆拿走1个,此时第一堆和第二堆数目相同
  2. 无论后手怎么拿,先手都在另外一堆石子中取走相同数量的石子即可。

解题思路

必胜状态和必败状态
在解决这个问题之前,先来了解两个名词:
必胜状态,先手进行某一个操作,留给后手是一个必败状态时,对于先手来说是一个必胜状态。即先手可以走到某一个必败状态。
必败状态,先手无论如何操作,留给后手都是一个必胜状态时,对于先手来说是一个必败状态。即先手走不到任何一个必败状态。

模板代码

#include<iostream>
using namespace std;
int main()
{int n;scanf("%d",&n);int res=0,x;   //为什么res可以初始化为0?while(n--)     //因为这是异或操作,0异或一个数,等于这个数本身{              //因此res可以初始化为0scanf("%d",&x);res^=x;}if(res) puts("Yes");else puts("No");return 0;
}

例题举例2:AcWing 892.台阶-Nim游戏

现在,有一个 n 级台阶的楼梯,每级台阶上都有若干个石子,其中第 i 级台阶上有 ai 个石子(i≥1)。
两位玩家轮流操作,每次操作可以从任意一级台阶上拿若干个石子放到下一级台阶中(不能不拿)。
已经拿到地面上的石子不能再拿,最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。

解题思路

此时我们需要将奇数台阶看做一个经典的Nim游戏,如果先手时奇数台阶上的值的异或值为0,则先手必败,反之必胜
证明:
先手时,如果奇数台阶异或非0,根据经典Nim游戏,先手总有一种方式使奇数台阶异或为0,于是先手留了奇数台阶异或为0的状态给后手
于是轮到后手:

  • ①当后手移动偶数台阶上的石子时,先手只需将对手移动的石子继续移到下一个台阶,这样奇数台阶的石子相当于没变,于是留给后手的又是奇数台阶异或为0的状态
  • ②当后手移动奇数台阶上的石子时,留给先手的奇数台阶异或非0,根据经典Nim游戏,先手总能找出一种方案使奇数台阶异或为0

因此无论后手如何移动,先手总能通过操作把奇数异或为0的情况留给后手,当奇数台阶全为0时,只留下偶数台阶上有石子
(核心就是:先手总是把奇数台阶异或为0的状态留给对面,即总是将必败态交给对面)

因为偶数台阶上的石子要想移动到地面,必然需要经过偶数次移动,又因为奇数台阶全0的情况是留给后手的,因此先手总是可以将石子移动到地面,当将最后一个(堆)石子移动到地面时,后手无法操作,即后手失败。

因此如果先手时奇数台阶上的值的异或值为非0,则先手必胜,反之必败!

模板代码

#include<iostream>
using namespace std;
int main()
{int n,x,res=0;scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&x);if(i&1) res^=x;}if(res) puts("Yes");else puts("No");return 0;
}

例题举例3:AcWing 893.集合-Nim游戏

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

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

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

解题思路




性质1修改成: S G ( k ) SG(k) SG(k)可以走到 0 − k − 1 0−k−1 0−k−1的任何一个状态


模板代码

#include<iostream>
#include<unordered_set>
#include<cstring>
using namespace std;
const int N=110,M=10010;
int s[N],f[M];
int k,n,h;
int sg(int x)
{if(f[x]!=-1) return f[x];     //记忆化搜索,只要算过了,就不重复算了unordered_set<int> c;   //用一个哈希表存储由起点产生的每个局面for(int i=0;i<k;i++)                        //递归的if(x-s[i]>=0)   //>=,不是>c.insert(sg(x-s[i]));for(int i=0;;i++)if(!c.count(i))            //计算sg(起点)return f[x]=i;
}
int main()
{memset(f,-1,sizeof(f));   //初始化为-1scanf("%d",&k);for(int i=0;i<k;i++) scanf("%d",&s[i]);scanf("%d",&n);int res=0;while(n--){scanf("%d",&h);res^=sg(h);}if(res) puts("Yes");else puts("No");return 0;
}

例题举例4:AcWing 894.拆分-Nim游戏

给定 n 堆石子,两位玩家轮流操作,每次操作可以取走其中的一堆石子,然后放入两堆规模更小的石子(新堆规模可以为 0,且两个新堆的石子总数可以大于取走的那堆石子数),最后无法进行操作的人视为失败。

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

解题思路

总数在操作过程中可能会变多,但是单堆的最大值会变小,所以这个过程是一定可以停止的。

模板代码

#include<iostream>
#include<cstring>
#include<unordered_set>
using namespace std;
const int N=110;
int n,a;
int s[N],f[N];
int sg(int x)
{unordered_set<int> c;if(f[x]!=-1) return f[x];for(int i=0;i<x;i++)          //拆分成两个局面for(int j=0;j<=i;j++)     //规定一个大一个小c.insert(sg(i)^sg(j));    //多个独立局面的SG值,等于这些局面SG值得异或和for(int i=0;;i++)//mex操作if(!c.count(i))return f[x]=i; //当递归回第一层时,返回SG(x1)的值,即要用来异或的值
}
int main()
{scanf("%d",&n);memset(f,-1,sizeof(f));int res=0;while(n--){scanf("%d",&a);res^=sg(a);}if(res) puts("Yes");else puts("No");return 0;
}

博弈论 思路及模板代码相关推荐

  1. 高斯消元法 思路及模板代码

    高斯消元法解线性方程组 思路及步骤 最后的到一个(近似)阶梯形矩阵 再把它化简成近似单位矩阵,即可得到解 模板代码 //题目背景:AcWing 883 #include<iostream> ...

  2. 【编辑器】unity自动化生成UI模板代码

    前言 在游戏制作用,UI的代码架构是固定的.为了快速开发,只需要获得一个完整的UI结构代码,然后编写对应的业务逻辑即可.所以,自动化生成模板代码是一件必不可少的事情. 环境 UI的架构通常使用MVC的 ...

  3. 剑指OFFER思路总结与代码分享——树篇(Java实现)

    剑指OFFER树相关 55-1 二叉树的深度 27 二叉树的镜像 54 二叉搜索树的第K大节点 32-II 从上到下打印二叉树 07 重建二叉树 68-I 二叉搜索树的最近公共祖先 68-II 二叉树 ...

  4. 模板模式详解、模板模式怎么用、模板模式模板代码

    模板模式详解.模板模式怎么用.模板模式模板代码 文章目录 模板模式详解.模板模式怎么用.模板模式模板代码 @[toc] 模板模式定义 使用场景 优点 代码实操 模板模式定义 在模板模式(Templat ...

  5. android dagger2 讲解,告别Dagger2模板代码:DaggerAndroid原理解析

    本系列所有文章: 概述 距离我的上一篇文章发布以来,有幸收获了一些朋友的认可,我很开心. 在上一篇文章中,我简单叙述了Dagger2这个库目前在Android开发中的一些短板,为什么我们学习Dagge ...

  6. vue文件快速生成模板代码

    vue文件快速生成模板代码 输入 vue 按 tab 键

  7. 为了提高工作效率:通过pycharm的模板代码减少重复工作

    摘要 在常见的业务开发场景下,经常要开发大量重复的代码,这里代码耗时但又必要,就像我们写分析报告一样,每次都要为固定的格式耗费精力.我们可以更加日常开发经验总结出一些常用的模板代码来帮助我们实现一秒五 ...

  8. 《大厂算法面试题目与答案汇总,剑指offer等常考算法题思路,python代码》V1.0版...

    为了进入大厂,我想很多人都会去牛客.知乎.CSDN等平台去查看面经,了解各个大厂在问技术问题的时候都会问些什么样的问题. 在看了几十上百篇面经之后,我将算法工程师的各种类型最常问到的问题都整理了出来, ...

  9. flask 常见关系模板代码

    以下罗列了使用关系型数据库中常见关系定义模板代码 一对多 示例场景: 用户与其发布的帖子(用户表与帖子表) 角色与所属于该角色的用户(角色表与多用户表) 示例代码 class Role(db.Mode ...

最新文章

  1. LeetCode Add Binary
  2. python语言跨平台语言吗_python属于跨平台语言吗?
  3. jquery动态添加列表后样式失效解决方式
  4. docker下安装Nginx的方法
  5. html input选择框样式修改,关于type=file的input框样式修改小结
  6. linux查看发ftp的ip地址,linux常用命令及学习小结(4)--IP设置、samba、ftp
  7. 双流棠湖中学怎么样_棠湖中学教师团队荣获四川省“最美教师团队”!
  8. oracle 物理表,【查询Oracle表实际物理使用大小】
  9. hdfs 多个文件合并_hadoop学习笔记3 hadoop程序将本地文件夹中多个文件,合并为一个文件并上传到hdfs中--梦飞翔的地方(梦翔天空)...
  10. jupyter可以打开HTML文件吗,Jupyter ~ 像写文章般的 Coding (附:同一个ipynb文件,执行多语言代码)...
  11. rhel5 给grub 加密,亲测!
  12. linux c 笔记 线程控制(一)
  13. 《Redis开发与运维》读书笔记三
  14. 第3章-线性概率模型(1)-logistics/probit模型
  15. 如何通过F12开发者工具保存网页中想要的视频资源
  16. 计算机弹奏简谱成都,赵雷《成都》简谱,分享给大家
  17. 黑鲨手机计算机科学技术器,黑鲨4Pro将PC的SSD存储科技带到手机端,真技术革命还假营销噱头?...
  18. 蚂蚁金服Java岗内推,quartz定时器的处理
  19. 毕业设计-基于协同过滤算法的旅游推荐系统
  20. OpenCV Flann

热门文章

  1. 微服务之SpringCloud服务调用
  2. 【CC++】打印日历
  3. 笔试面试题目:正方形的判断
  4. [心得记录] 9种思维定势
  5. Centos7安装wps办公软件
  6. 服务器管理器如何添加共享账号,大势至共享文件管理系统如何添加账号
  7. Mac系统下Maven的下载与配置
  8. Markdown:五分钟Markdown教程
  9. 事件代理(事件委托)、事件冒泡
  10. 虚拟机多开无网络连接