【博弈论】Nim游戏
Definition
这样的游戏被称为Nim游戏:
1、有两个玩家,轮流进行操作
2、是公平游戏。即面对同一局面两个玩家所能进行的操作是相同的。例如中国象棋不是公平游戏。因为面对同一个局面,红方只能移动红色棋子而不能移动黑方棋子,黑房同理。
3、一个玩家是输掉当且仅当他无法进行操作。例如如果是两个人轮流取石子的游戏,那么一个玩家输掉当且仅当他面前没有石子了。因为他下面无法进行取石子的操作。
一般的,Nim游戏指两个玩家轮流在好几堆东西中取物品,不能夸堆取,无法操作判负。
Solution
对于Nim游戏的解法,因为状态显然是不可逆的,所以可以对状态的转移图进行拓扑排序然后DP求解。但是对于大部分博弈题目,状态多的难以计算,所以需要考虑更简单的方法。
结论:一个Nim游戏中的状态是必败状态当且仅当每个子游戏的异或和为0.
这里子游戏代表构成Nim游戏中最基础的游戏。例如两个人轮流取三堆石子的游戏是三个取一堆石子的游戏组合而成的。对于每个子游戏显然可以用一个正整数代表当前的状态,即还剩多少石子。Nim游戏的子游戏状态异或和为\(0\),则必败。
证明:我有一个绝妙的想法,可惜这里写不开
对于一个异或和不为\(0\)的状态,那么他是必胜态。
考虑在一个必胜态下如何进行下一步。
设异或和是\(X\)。设\(X\)二进制的最高为1位是第\(k\)位。
那么显然存在至少一个状态使得他们二进制第\(k\)位为1。否则第k位异或和应该是0。
那么就任选一个第k位是1的状态,设他的状态是\(Y\),那么将他可以将\(Y\)这一堆取成\(Z=X~xor~Y\)那么得到的状态是必败状态。
证明如下:
首先,\(Y\)可以取成\(Z\)当且仅当\(Z~\leq~Y\)。首先证明\(Z~\leq~Y\)。
因为\(Y\)和\(X\)第\(k\)位都是\(1\),更高位都是\(0\)。那么异或后\(Z\)第\(k\)位一定是\(0\),更高位显然是\(0\)。所以\(Z\)的位数比\(Y\)的位数要少。那么显然\(Z~\leq~Y\)。
下面证明更改后的状态是必败状态
根据\(Z=X~xor~Y\),并且\(A~xor~A=~0~\)。可得:
更改后的状态
\(S~=~X~xor~Y~xor~Z~=~X~xor~Y~xor~(~X~xor~Y~)\)
\(=~(~X~xor~Y~)~xor~(~X~xor~Y~)~=~0~\)
一定是一个必败状态。
Example
Description
输入k及k个整数n1,n2,…,nk,表示有k堆火柴棒,第i堆火柴棒的根数为ni;接着便是你和计算机取火柴棒的对弈游戏。取的规则如下:每次可以从一堆中取走若干根火柴,也可以一堆全部取走,但不允许跨堆取,也不允许不取。
Input
第一行,一个正整数k
第二行,k个整数n1,n2,…,nk
Output
如果是先取必胜,请在第一行输出两个整数a,b,表示第一次从第b堆取出a个。第二行为第一次取火柴后的状态。如果有多种答案,则输出<b,a>字典序最小的答案(即b最小的前提下a最小)。
如果是先取必败,则输出“lose”。
Sample Input_1
3
3 6 9
Sample Output_1
4 3
3 6 5
Sample Input_2
4
15 22 19 10
Sample Output_2
lose
Hint
\(k~\leq~500000\)
\(n_i~\leq~1e9\)
Solution
板子题要啥solution
Code
#define rg register
#define ci const int
#define cl const long long int
typedef long long int ll;
namespace IO {
char buf[90];
}
template<typename T>
inline void qr(T &x) {
char ch=getchar(),lst=' ';
while(ch>'9'||ch<'0') lst=ch,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(lst=='-') x=-x;
}
template<typename T>
inline void write(T x,const char aft,const bool pt) {
if(x<0) x=-x,putchar('-');
int top=0;
do {
IO::buf[++top]=x%10+'0';
x/=10;
} while(x);
while(top) putchar(IO::buf[top--]);
if(pt) putchar(aft);
}
template<typename T>
inline T mmax(const T a,const T b) {if(a>b) return a;return b;}
template<typename T>
inline T mmin(const T a,const T b) {if(a<b) return a;return b;}
template<typename T>
inline T mabs(const T a) {if(a<0) return -a;return a;}
template<typename T>
inline void mswap(T &a,T &b) {
T temp=a;a=b;b=temp;
}
const int maxn = 500010;
int n,ans;
int MU[maxn];
int main() {
qr(n);
for(rg int i=1;i<=n;++i) {
qr(MU[i]);ans^=MU[i];
}
if(!ans) {
puts("lose");return 0;
}
int _temp=1<<30;
while(!( _temp & ans )) _temp>>=1;
for(rg int i=1;i<=n;++i) if(MU[i] & _temp){
int z=ans^MU[i];
write(MU[i]-z,' ',true);write(i,'\n',true);
for(rg int j=1;j<=n;++j) {
if(j != i) write(MU[j],' ',true);
else write(z,' ',true);
}
break;
}
return 0;
}
Summary
Nim游戏是必败态当且仅当子游戏状态异或和为0。否则是必胜态。通过必胜态一定可以通过一步操作变成必败状态。
【博弈论】Nim游戏的更多相关文章
- 博弈论之Nim游戏
Nim游戏是组合游戏(Combinatorial Games)的一种,属于“Impartial Combinatorial Games”(以下简称ICG). 通常的Nim游戏的定义是这样的:有若干堆石 ...
- 博弈论入门之nim游戏
更好的阅读体验点这里 nim游戏 nim游戏 有两个顶尖聪明的人在玩游戏,游戏规则是这样的: 有\(n\)堆石子,两个人可以从任意一堆石子中拿任意多个石子(不能不拿),没法拿的人失败.问谁会胜利 ni ...
- 【博弈论】浅谈泛Nim游戏
Nim游戏在ACM中碰到了,就拎出来写写. 一般Nim游戏:有n堆石子,每堆石子有$a_i$个,每次可以取每堆石子中$[0,a_i-1]$,问先手是否有必胜策略. 泛Nim游戏:每堆石子有$a_i$个 ...
- [您有新的未分配科技点]博弈论入门:被博弈论支配的恐惧(Nim游戏,SG函数)
今天初步学习了一下博弈论……感觉真的是好精妙啊……希望这篇博客可以帮助到和我一样刚学习博弈论的同学们. 博弈论,又被称为对策论,被用于考虑游戏中个体的预测行为和实际行为,并研究他们的应用策略.(其实这 ...
- Nim游戏与SG函数 ——博弈论小结
写这篇博客之前,花了许久时间来搞这个SG函数,倒是各路大神的论文看的多,却到底没几个看懂的.还好网上一些大牛博客还是性价比相当高的,多少理解了些,也自己通过做一些题加深了下了解. 既然是博弈,经典的N ...
- BZOJ_3105_[cqoi2013]新Nim游戏_线性基+博弈论
BZOJ_3105_[cqoi2013]新Nim游戏_线性基+博弈论 Description 传统的Nim游戏是这样的:有一些火柴堆,每堆都有若干根火柴(不同堆的火柴数量可以不同).两个游戏者轮流操作 ...
- (博弈论)51NOD 1069 Nim游戏
有N堆石子.A B两个人轮流拿,A先拿.每次只能从一堆中取若干个,可将一堆全取走,但不可不取,拿到最后1颗石子的人获胜.假设A B都非常聪明,拿石子的过程中不会出现失误.给出N及每堆石子的数量,问最后 ...
- 洛谷$P$4301 $[CQOI2013]$新$Nim$游戏 线性基+博弈论
正解:线性基 解题报告: 传送门! 这题其实就是个博弈论+线性基,,,而且博弈论还是最最基础的那个结论,然后线性基也是最最基础的那个板子$QwQ$ 首先做这题的话需要一点点儿博弈论的小技能,,,这题的 ...
- 博弈论入门——Nim游戏引入
说实话,我真的对这个游戏看得是一脸懵逼,因为(我太弱了)我没有明白一些变量的意思,所以一直很懵,现在才明白,这让我明白博弈论(还可以骗钱)博大精深; 以下是我自己思考的过程,也许不严谨,但是最终明白了 ...
- 博弈论(nim游戏,SG函数)
说到自己,就是个笑话.思考问题从不清晰,sg函数的问题证明方法就在眼前可却要弃掉.不过自己理解的也并不透彻,做题也不太行.耳边时不时会想起alf的:"行不行!" 基本的小概念 这里 ...
随机推荐
- JMeter随机上传附件
方法一: 1.添加一个前置Beanshell 2.输入代码: File folder = new File("/path/to/your/folder/with/audiofiles&quo ...
- 聊聊Bug引发事故该不该追求责任
最近读极客时间朱赟的一篇文章有感,在这也聊一下,在互联网的公司大多数以迭代的方式上线需求,节奏一般都比较快,经常会一个需求当天来了第二天就上线,开发和测试时间总共就两天,中间还穿插着别的需求测试,不像 ...
- 小程序页面的四种文件(JSON、WXML、WXSS、JS)加载顺序
一个小程序页面由四种文件组成: 1)json 页面配置文件 2)js 页面逻辑文件(必需) 3)wxml 页面结构文件(必需) 4)wxss 页面样式文件 这四个文件的加载顺序: 第一步: 加载页面j ...
- 【wx:for】小程序列表渲染的使用说明
wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件. 默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item,即: {{index}} . {{it ...
- vue watch监控对象
1.普通的watch data() { return { frontPoints: 0 } }, watch: { frontPoints(newValue, oldValue) { console. ...
- 在github上面创建属于自己的个性主页
圈子里面越来越多的同事在github上面创建自己的项目文档,那里确实高手云集,海内外的技术大牛小牛们都在那儿有一席之地,为“helloword”贡献自己. 以上感慨略过... 这几日正想创建一个自己的 ...
- [Clr via C#读书笔记]Cp11事件
Cp11事件 类型之所以提供事件通知功能,是因为类型维护了一个已登记方法的列表,事件发生后,类型将通知列表登记的所有方法: 事件模型建立在委托的基础上.委托是调用回调方法的一种类型安全的方式. 设计事 ...
- docker创建redis镜像
pull redis 镜像 创建redis的镜像有几种方式,可以直接从仓库中拉取,也可以采用dockerfile文件自己编译创建. 基于已有的redis镜像,docker可以采用run,或者creat ...
- LeetCode 386——字典序的第 K 小数字
1. 题目 2. 解答 字典序排数可以看做是第一层节点分别为 1-9 的十叉树,然后我们在树上找到第 K 小的数字即可.因此,我们需要分别统计以 1-9 为根节点的每个树的节点个数.如果 K 小于当前 ...
- Python3 小工具-UDP发现
from scapy.all import * import optparse import threading import os def scan(ip): pkt=IP(dst=ip)/UDP( ...