最近在数学这一块搞了蛮多题目,已经解决了数论基础,线性代数(只有矩阵,行列式待坑),组合数学中的一些简单问题。所以接下来不可避免的对博弈论这一哲学大坑开工。

当然,由于我很,所以也只能从最基础最容易的部分讲起了。

这次主要介绍两个基本模型:Bash Game&&Nim Game,还是比较经典的

下面开始讲

1.Bash Game

Bash Game(巴什博弈)是一种零基础的入门题目,它的基本模型大概是这样的:

一堆石子共n个,两人轮流从中取石子,规定每次至少取一个,最多取m个,最后取光者得胜。问两人博弈,他们都采用最聪明的策略,问最后谁可以必胜。

首先我们从小开始分析:

  • 当m>=n时,先手可以一把抓完石子,这样先手必胜

  • 当n=m+1时,先手无论怎么抓,都会留下1~m个石子,这样后手一把就可以抓完,这样先手必败

  • 当m+1<n<2*(m+1)时,先手只要抓适当的石子就可以剩下m+1个石子,然后后手必输,那么先手必胜

  • 当n=2*(m+1)时,后手可以采取这种策略,当先手抓x个时,后手就抓m+1-x个,这样就会把m+1的情况送给先手,那么先手必败

  • ......

所以通过上面的分析我们很容易得出:当n%(m+1)==0时,先手必败;否则先手必胜

这个很简单吧,因为谁先面对k*(m+1)(k为正整数)这种局面就必定失败。因为一方可以每次让你们两个取得石子和为m+1导致另一方失败。

这个问题还有一些变形,比较经典的就是:把一个数从0开始不断增加,每次增加的范围都是1~k,谁先让数增加到n就Win||Lose

这个直接转化为Bash Game做一下即可

这里给几道例题&&CODE(以下例题都来自HDU

1846

Bash博弈的板子题,直接上即可

CODE

#include<cstdio>
using namespace std;
int t,n,m;
inline char tc(void)
{
static char fl[100000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
x=0; char ch=tc();
while (ch<'0'||ch>'9') ch=tc();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
read(t);
while (t--)
{
read(n); read(m);
puts(n%(m+1)?"first":"second");
}
return 0;
}

2149

这就是那种变式的情况,我们转化一下在做转化个屁,至于输出方案的话特判一下即可

CODE

#include<cstdio>
using namespace std;
int n,m;
inline void write(int x)
{
if (x/10) write(x/10);
putchar(x%10+'0');
}
int main()
{
register int i;
while (scanf("%d%d",&m,&n)!=EOF)
{
if (n>=m)
{
for (i=m;i<n;++i)
write(i),putchar(' '); write(n); putchar('\n');
} else
if (m%(n+1)) write(m%(n+1)),putchar('\n'); else puts("none");
}
return 0;
}

2138

同上,Bash Game直接上即可

CODE

#include<cstdio>
using namespace std;
int t,n,m;
inline char tc(void)
{
static char fl[100000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
x=0; char ch=tc();
while (ch<'0'||ch>'9') ch=tc();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
read(t);
while (t--)
{
read(n); read(m);
puts(n%(m+1)?"Grass":"Rabbit");
}
return 0;
}

4764

这道题就注意一下大于等于n你就输了,所以n要减一

CODE

#include<cstdio>
using namespace std;
int n,m;
inline char tc(void)
{
static char fl[100000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
x=0; char ch=tc();
while (ch<'0'||ch>'9') ch=tc();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (;;)
{
read(n); read(m);
if (!n&&!m) break;
puts((n-1)%(m+1)?"Tang":"Jiang");
}
return 0;
}

2.Nim Game

这其实是Bash Game的进化版,但是思维深度上了好几个台阶

首先我们看基本模型:

地上有n堆石子,每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取完,不能不取。每次只能从一堆里取。最后没石子可取的人就输了。假如甲是先手,且告诉你这n堆石子的数量,他想知道是否存在先手必胜的策略。

这是不是很复杂,首先我们考虑数据小的情况:

  • 只有一堆石子时,除非没有石子,否则先手一把抓完即可

  • 有两堆石子时,后手只需要跟随先手的动作即可

  • ......(后面的根本分析不出来好吧)

但是在我们之前已经有大神成功证明了一个神奇的结论

当n堆石子的数量异或和等于0时,先手必败,否则先手必胜

证明请移步至attack dalao's blog

很懵逼对吗其实我也是,那么让我们来感性理解一下(以下的说明仅为个人理解,几乎没有任何理论依据,请选择阅读)

首先由于全部都是0的时候就失败了,所以我们可以认为当它们的异或和为0就是必败态

这样我们先手是如果异或和为0那么就输了

如果不是呢,我们就可以通过一种猥琐的方法来获胜(就是上面讲的方法)

我们可以形象地认为它与Bash Game中先手先取得只剩下k*(m+1)然后通过让和始终为m+1来取胜

然后这就是神奇的Nim Game

这里有一道模板题Luogu P2197 nim游戏

由于就是裸的Nim Game,这里就直接上CODE了

#include<cstdio>
using namespace std;
int t,n,x,tot;
inline char tc(void)
{
static char fl[100000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
x=0; char ch=tc();
while (ch<'0'||ch>'9') ch=tc();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
register int i; read(t);
while (t--)
{
for (read(n),tot=0,i=1;i<=n;++i)
read(x),tot^=x;
puts(tot?"Yes":"No");
}
return 0;
}

当然这只是博弈论的入门,一些真正强力的东西如SG函数&&MINMAX等东西还是一脸懵逼

浅谈博弈论中的两个基本模型——Bash Game&&Nim Game的更多相关文章

  1. 浅谈Java中的equals和==(转)

    浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str ...

  2. 浅谈Linux中的信号处理机制(二)

    首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...

  3. 浅谈Java中的对象和引用

    浅谈Java中的对象和对象引用 在Java中,有一组名词经常一起出现,它们就是“对象和对象引用”,很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起 ...

  4. 浅谈Java中的equals和==

    浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: String str1 = new String("hello"); String str2 = ...

  5. 转【】浅谈sql中的in与not in,exists与not exists的区别_

    浅谈sql中的in与not in,exists与not exists的区别   1.in和exists in是把外表和内表作hash连接,而exists是对外表作loop循环,每次loop循环再对内表 ...

  6. 浅谈iOS中的userAgent

    浅谈iOS中的userAgent   User-Agent(用户代理)字符串是Web浏览器用于声明自身型号版本并随HTTP请求发送给Web服务器的字符串,在Web服务器上可以获取到该字符串. 在公司产 ...

  7. 浅谈JavaScript中的闭包

    浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...

  8. 浅谈sql中的in与not in,exists与not exists的区别

    转 浅谈sql中的in与not in,exists与not exists的区别   12月12日北京OSC源创会 —— 开源技术的年终盛典 »   sql exists in 1.in和exists ...

  9. 浅谈Java中的深拷贝和浅拷贝(转载)

    浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: ...

随机推荐

  1. 《Inside C#》笔记(五) 方法

    方法用来体现类的行为. 一 相关概念 a) ref和out 通常一个方法只能返回一个值,但如果确实需要返回多个值时,可以使用ref或out.如果方法的参数被标注为ref或out,在调用该方法时,会传递 ...

  2. shell下变量比较最佳实践

    https://stackoverflow.com/questions/13617843/unary-operator-expected If you know you're always going ...

  3. [20171211][转载]如何实现dbms_output输出没有打开serveroutput on.txt

    [20171211]如何实现dbms_output输出没有打开serveroutput on.txt http://orasql.org/2017/12/10/sqlplus-tips-8-dbms_ ...

  4. Linux 运行进程实时监控pidstat命令详解

    简介 pidstat主要用于监控全部或指定进程占用系统资源的情况,如CPU,内存.设备IO.任务切换.线程等.pidstat首次运行时显示自系统启动开始的各项统计信息,之后运行pidstat将显示自上 ...

  5. matplotlib numpy scipy 的安装

    一:windows 端的安装 #cmd指令 python -m pip install --user numpy scipy matplotlib ipython jupyter pandas sym ...

  6. webpack热更新和常见错误处理

    时间:2016-11-03 10:50:54 地址:https://github.com/zhongxia245/blog/issues/45 webpack热更新 一.要求 局部刷新修改的地方 二. ...

  7. Android Studio入门问题汇总

    1.如何设置 AS 中的字体大小 2.如何切换 AS 的皮肤颜色,默认为黑色,修改为白色,改为 default 3.首次安装 Android Studio并打开时,如果创建了一个新工程并将工程保存在另 ...

  8. 【Ansible 文档】提示、推荐、注意事项

    1. 查看 详细 信息 如果你想要查看成功模块和不成功的详细输出,使用 --verbose 标识 2. 检查 playbook 的语法 使用 ansible-playbook 的 --syntax-c ...

  9. usb-cam (3)摄像机标定文件-ORB-SLAM标定文件

    http://www.luohanjie.com/2017-04-05/the-problem-of-calibration-data-in-orb-slam2.html ORB_SLAM2中标定数据 ...

  10. 对Promise的理解?

    ES6原生提供了promise对象 所谓Promise,就是一个对象,用来传递异步操作的消息.它代表了某个未来才会知道结果的事件(通过是一个异步操作),并且这个事件提供统一的API,可供进一步处理 P ...