博弈论--Nim游戏

Nim游戏是博弈论中最经典的模型(之一),它又有着十分简单的规则和无比优美的结论 Nim游戏是组合游戏(Combinatorial Games)的一种,准确来说,属于“Impartial Combinatorial Games”

Nim游戏具体游戏规则为:有n堆石子,两名选手,每个选手可以拿一堆石子中的任意多个,谁面对无石子可拿的情况时就为负。

定义:先手必败状态 定义为走不到任何一个必败状态,为状态P

   先手必胜状态 定义为能够走到一个必败状态,为状态N

 根据定义出发,模拟(2,2)的必败场景

 

 

 因为(0,2)能到(0,0),所以(0,2)为N状态

因为(1,1)只有(0,1)一个后继态,而(0,1)为N态,所以(1,1)为P态。所以(1,2)为N态

所以(2,2)有且只有两个N态,所以(2,2)是一个P态

即面对(2,2)的情况,先手必败。

 

既然如此,给定n堆石子就可以求出当前状态是N或P,但是时间复杂度过高哪怕用上记忆化搜索或者DP,时间复杂度为O ( max(a1,a2...an) ),而0<=ai<=1e9

显然是不能再1s钟内算出答案。

所以数学家们想到了一个绝妙的方法:利用异或

 

记 t = a1^a2^a3^...^an

若t=0,则当前状态为P,即先手必败

否则则为N,即先手必胜

证明:若需证明上述定理,则需要证明

(1)最终的全零态被判定为P态

(2)被判定为N态的一定可以移动到某一个P态

(3)被判定为P态的,一定不能移动到某一个P态

 

 

 

 所以可以直接通过上边的定理得出当前是一个P态或者N态

复制代码
 1 #include<iostream>
 2 using namespace std;
 3 int main(void){
 4     int n;
 5     cin>>n;
 6     int res;
 7     cin>>res;
 8     for(int i=1;i<n;i++){
 9         int t;
10         cin>>t;
11         res^=t;
12     }
13     if(res==0){
14         cout<<"No";
15     }else{
16         cout<<"Yes";
17     }
18 }
复制代码

 

 

Nim游戏变种--台阶Nim游戏

题目:https://www.acwing.com/problem/content/894/

 

 

复制代码
 1 #include<iostream>
 2 using namespace std;
 3 int main(void){
 4     int n;
 5     cin>>n;
 6     int res=0;
 7     for(int i=0;i<n;i++){
 8         int x;
 9         cin>>x;
10         if(i%2==0)
11             res^=x;
12     }
13     if(res) puts("Yes");
14     else puts("No");
15     return 0;
16 }
复制代码

 

posted on   greenofyu  阅读(412)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示