牛客杯 - 巴什博弈和威佐夫博弈

巴什博弈

问题描述

  • 一共n个物品,两个人轮流取且一次最多取m个最少取1个,谁先去完谁赢。

解释

  • 假设n=(m+1)*r+s,其中r为任意自然数,s为正整数。先手只要取走s个那么剩下的就是m+1的倍数,只要先手根据后手拿的个数拿走对应的个数让剩下的个数一直维持在m+1的整数倍,那么最后拿完的一定是先手。
  • 以此类推,如果上来的n正好是m+1的倍数,那么不管先手拿多少都会让n变为(m+1)*r+s,这样就可以看成“先手变成了后手,后手变成了先手”,那么后手就必赢
  • 综上所述,如果n为m+1的整数倍,那么后手必赢;如果n不是m+1的整数倍,那么先手必赢。

拓展

  • 如果是先拿完的输呢?
  • 那么赢的那个人就肯定会给对方留最后一张,这也就是说先拿完n-1个物品的人就赢了
  • 因此,如果n-1是m+1的整数倍,那么后手赢;如果n-1不是m+1的整数倍,那么先手赢。

代码

<---------------- 先拿完的赢 ----------------->
#include<iostream>
using namespace std;

int main(){
    long long count;
    long long n,k;
    bool res[1000000];
    cin>>count;
    for(int i=0;i<count;i++){
        cin>>n>>k;
        if(n%(k+1)!=0)
            res[i]=true;
        else res[i]=false;
    }
    for(int i=0;i<count;i++){
        if(res[i])
            cout<<"First Man Win!"<<endl;
        else
            cout<<"Last Man Win!"<<endl;
    }
    return 0;
}

<---------------- 先拿完的输 ----------------->


#include<iostream>
using namespace std;

int main(){
    long long count;
    long long n,k;
    bool res[1000000];
    cin>>count;
    for(int i=0;i<count;i++){
        cin>>n>>k;
        if((n-1)%(k+1)!=0)
            res[i]=true;
        else res[i]=false;
    }
    for(int i=0;i<count;i++){
        if(res[i])
            cout<<"First Man Win!"<<endl;
        else
            cout<<"Last Man Win!"<<endl;
    }
    return 0;
}

威佐夫博弈

问题描述

  • 两堆物品个数记为(a,b),两个人轮流从任意一堆中取出至少一个或者同时从两堆中取出同样多的物品,规定每次至少取一个,至多不限,最后取光者胜利。

解释

  • 先手方必输的局面成为奇异局势,那么奇异局势有:
    • (0,0)
    • (1,2)
    • (3,5)
    • ​ ......
    • (a,b)
  • 根据分析可知,奇异局势的a是b-a的差值的1.618倍,其中a是两者中较小的那一个。

代码

#include<iostream>
#include<cmath>
using namespace std;

int main(){
    double r=(1.0+sqrt(5.0))/2.0;
    int m;
    cin>>m;
    bool res[1000000];
    for(int i=0;i<m;i++){
        int n,x,a,b;
        cin>>n>>x;
        if(x-1>=n-x){
            a=n-x;
            b=x-1;
        }
        else{
            a=x-1;
            b=n-x;
        }
        if((int)((b-a)*r)!=a)//注意这个,需要类型转换,否则比较会出错。
            res[i]=true;
        else res[i]=false;
    }
    for(int i=0;i<m;i++){
        if(res[i])
            cout<<"First Man Win!"<<endl;
        else
            cout<<"Last Man Win!"<<endl;
    }
    return 0;
}
posted @ 2021-01-31 13:07  MrDaddy  阅读(98)  评论(0)    收藏  举报