博弈论--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 2020-12-22 16:18  greenofyu  阅读(359)  评论(0编辑  收藏  举报