Nim游戏——简单博弈论

简介: Nim游戏——简单博弈论

原题链接

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


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


输入格式

第一行包含整数n。


第二行包含n个数字,其中第 i 个数字表示第 i 堆石子的数量。


输出格式

如果先手方必胜,则输出“Yes”。


否则,输出“No”。


数据范围

1≤n≤105,

1≤每堆石子数≤109

输入样例:

2

2 3

输出样例:

Yes


先上一波代码

#include<bits/stdc++.h>
using namespace std;
int main(){
  int n;
  int res=0;
  cin>>n;
  while(n--){
    int x;
    cin>>x;
    res^=x;
  }
  if(res) cout<<"Yes"<<endl;
  else cout<<"No"<<endl;
  return 0;
} 

该题为简单的 博弈论题目,一般博弈论题目有如下特征:


1.有两名选手;


2.两名选手交替操作,每次一步,每步都是在有限的合法集合中选取一种进行;


3.在任何情况下,合法操作只取决于情况本身,与选手无关;


4.游戏的败北条件为:当某位选手需要进行操作时,当前没有任何可以执行的合法操作,则该选手败北。

先来介绍Nim里的两种状态,先手必败状态和先手必胜状态。
前者是先手走不到任何一个必败状态,即后手无法是必败状态,先手必败。
后者即先手可以走到某个必败状态,此时为后手操作,后手必败。

Nim游戏中有个经典结论:若a1^a2…an==0 则先手必败。

我们可以从简单的数据入手,比如有两堆石子的数量分别为2、3。那么是不是先手必胜呢。我们可以先用结论及代码验证一下。

#include<bits/stdc++.h>
using namespace std;
int main(){
  int a1 = 2 , a2 = 3 ;
  if(a1^a2==0) puts("Win");
  else puts("Lose");
  return 0;
}

运行结果如图

60a6bcefe26f4b118e50f46e4d0afd1d.png

那么我们现在可以模拟一下具体过程,前提是每个人每一步都是最优策略。先手从石子数为3的堆里取走一个石子,此时变为2 2,接下来不论后手做任何操作,先手只需在另一堆石子里做相同的操作,这样就再次使得两堆石子的数目一样。如此循环下去,一定是后手遇到必败状态,先手胜利。

接下来进行简单的证明一下:

首先,当所有的堆的石子数均为0时,异或值也是0,即不能进行任何操作,先手必败。

然后,如果异或值不为零,即a1^a2…an= k(k为非零常数),先手一定可以某种操作(即从某堆石子中拿走部分石子)让异或值变为0,此时后手走到了必败态,先手必胜。(具体为什么是异或值还有待探索)

假设k的二进制表示中最高的一位1是第x位, 那么在a1-an中必存在有一个数ai的第x位是1;那么ai^x<ai(ai的第k位由1变为0),我们可以从ai个石子中拿走ai-ai ^x 个石子(操作一定合法),这样的话所有的数的异或值就是0。

最后,我们来证明如果a1^a2…an=0,无论如何拿,所有数的异或值一定不是0。反证法可证。


具体为什么是异或值为0,可以参考K-Nim游戏;


Nim还有很多变形,学习中。

扔一道台阶Nim的题吧 惊奇队长和灭霸的决战 来自临沂大学新生赛

蓝桥杯历年试题 高僧斗法 也是如此

最后放一篇写的很好的高僧斗法的题解


不当之处,请多指教。

目录
相关文章
|
6月前
|
人工智能 决策智能
博弈论:Nim游戏
博弈论:Nim游戏
|
6月前
【力扣】292. Nim 游戏
【力扣】292. Nim 游戏
|
6月前
|
C++
Nim 游戏(C++)
Nim 游戏(C++)
71 0
|
决策智能
SG函数Nim游戏博弈论
SG函数Nim游戏博弈论
83 0
SG函数Nim游戏博弈论
|
机器学习/深度学习 决策智能
博弈论-nim 游戏
博弈论-nim 游戏
158 0
博弈论-nim 游戏
|
机器学习/深度学习
LightOJ1186——Incredible Chess(nim游戏)
LightOJ1186——Incredible Chess(nim游戏)
60 0
|
算法
算法题每日一练---第75天:Nim 游戏
你和你的朋友,两个人一起玩 Nim 游戏。
326 0
算法题每日一练---第75天:Nim 游戏