Nim博弈两题

来源:互联网 发布:js实现隐藏显示 编辑:程序博客网 时间:2024/05/01 17:38

一、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博弈的内容。

0 0
原创粉丝点击