Nim博弈两题

一、Nim博弈简介

1、游戏规则

设有k堆物品,(k>=1)各堆分别含有n1,n2,n3,……….nk件物品,游戏过程为:
(1)两个游戏者交替进行游戏;
(2)当轮到每个游戏者取子时,选择其中的一堆,并从所选的堆中取走至少一件物品(可以取走该堆中所有物品);
(3)直到所有堆为空。

2、获胜条件

在Nim博弈中一般有两种情形,分别为:
(1)最后取子的人获胜
(2)最后取子的人失败

3、解题方法

(1)针对情形1,即最后取子的人获胜时,首先求所有堆的物品数的异或:k=n1^n2^n3………nk,然后判断每一堆的数目,若某一堆的数目ni^k < ni,则认为先手从这一堆开始取的时候可以获胜,并且所取得数目必须为ni-k;
(2)针对情形2,即最后取子的人失败时,同样的求所有数目的异或:k=n1^n2^n3………nk,若得到的k=0,则认为后手胜,否则先手胜,另外,需要特别注意的是:若所有堆的数目均为1的时候,必须特判,因为按照之前的方法判断会得出相反的错误结论,此时若有奇数堆,则后手胜,若有偶数堆,则先手胜。

二、两道例题

1、http://acm.hdu.edu.cn/showproblem.php?pid=1907
AC代码:

using namespace std;
int main()
{
    int t;
    int n;
    int res=0;
    int temp;
    cin>>t;
    while(t--)
    {
        bool flag = false;
        res=0;
        cin>>n;
        for(int i=0;i<n;i++)
        {
            cin>>temp;
            if(temp>1)flag = true;
            res = res^temp;
        }
        if(flag)
        {
            if(res)cout<<"John"<<endl;
            else cout<<"Brother"<<endl;
        }
        else
        {
            if(n%2==0)cout<<"John"<<endl;
            else cout<<"Brother"<<endl;
        }
    }
    return 0;
}

2、http://acm.hdu.edu.cn/showproblem.php?pid=2509
AC代码:

using namespace std;
int main()
{
    int n;
    int temp;
    int res=0;
    while(cin>>n)
    {
        bool flag = false;
        res=0;
        for(int i=0;i<n;i++)
        {
            cin>>temp;
            if(temp>1)flag = true;
            res = res^temp;
        }
        if(flag)
        {
            if(res)cout<<"Yes"<<endl;
            else cout<<"No"<<endl;
        }
        else
        {
            if(n%2==0)cout<<"Yes"<<endl;
            else cout<<"No"<<endl;
        }
    }
    return 0;
}

这两道题都非常简单,都是对Nim博弈结论的基础应用,相信只要掌握了Nim博弈的原理就会非常简单。
当然,本篇博客所写的只是结论的直接应用,若想知道为什么可以这样做,寻求背后的指导理论,可以搜索关于Nim博弈的内容。

你可能感兴趣的:(ACM,nim博弈)