基础博弈专题

感觉,目前主要是能够将具体的题目转化为某一种博弈类型,这样根据类型来做,会好很多。

首先,是比较基础的

巴什博奕(Bash Game):

根据这三个性质去推理的话,下面这几道题目应该可以很快解决

(1) 所有终结点是必败点(P点);
 
(2) 从任何必胜点(N点)操作,至少有一种方法可以进入必败点(P点);
 
(3)无论如何操作, 从必败点(P点)都只能进入必胜点(N点).
hdu1846
#include<iostream>
using namespace std;
int main()
{
    int n,m,cas;
    scanf("%d",&cas);
    while(cas--)
    {
        scanf("%d %d",&n,&m);
        if(n<=m)
            puts("first");
        else if(n%(m+1)==0)
            puts("second");
        else puts("first");
    }
    return 0;
}

 hdu 2147

#include<iostream>
using namespace std;
int main()
{
    int n,m;
    while(scanf("%d %d",&n,&m)==2&&(n||m))
    {
        if(n%2==1 && m%2==1)
            puts("What a pity!");
        else puts("Wonderful!");
    }
    return 0;
}

 hdu2149

#include<iostream>
using namespace std;
int main()
{
    int m,n;
    while(scanf("%d %d",&m,&n)==2)
    {
        if(n>=m)
        {
            for(int i=m;i<n;i++)
                printf("%d ",i);
            printf("%d\n",n);
            continue;
        }
        int flag=0;
        for(int i=1;i<=n;i++)
        {
            if(m-i<=n)
                continue;
            if((m-i)%(n+1)==0)
            {
                if(!flag)
                    printf("%d",i),flag=1;
                else printf(" %d",i);
            }
        }
        if(flag)puts("");
        else puts("none");
    }
    return 0;
}

 hdu2188

#include<iostream>
using namespace std;
int main()
{
    int n,m,cas;
    scanf("%d",&cas);
    while(cas--)
    {
        scanf("%d %d",&n,&m);
        if(n<=m)
        {
            puts("Grass");
            continue;
        }
        if(n%(m+1)==0)
            puts("Rabbit");
        else puts("Grass");
    }
    return 0;
}

 接下来是

(二)威佐夫博奕(Wythoff Game):有两堆各若干个物品,两个人轮流从某一堆或同
时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。

嘿嘿,没做过类型的题目。
再接下来,是
比较重点的

(三)尼姆博奕(Nimm Game):有三堆各若干个物品,两个人轮流从某一堆取任意多的
物品,规定每次至少取一个,多者不限,最后取光者得胜。

主要涉及到了异或操作,关于这方面,感觉这篇博文介绍的还不错http://blog.sina.com.cn/s/blog_8f06da990100uwl1.html

hdu1849

#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
	int a,n;
	while(scanf("%d",&n)==1 && n)
	{
		a=0;
		int b;
		for(int i=0;i<n;i++)
		{
			scanf("%d",&b);
			a^=b;
		}
		if(a!=0)
			puts("Rabbit Win!");
		else puts("Grass Win!");
	}
	return 0;
}

 hdu1850

#include<stdio.h>
int main()
{
    int n,s[110],i,sum,count;
    while(scanf("%d",&n)!=EOF&&n)
    {
        sum=0;count=0;
        for(i=0;i<n;i++)
        {
            scanf("%d",&s[i]);
            sum=sum^s[i];
        }
        for(i=0;i<n;i++)
        {
            if(s[i]>(sum^s[i]))
                count++;
        }
        printf("%d\n",count);
    }
    return 0;
}

 再接下来就是博弈的经典所在了,关于sg函数

同样,在上面的博文里面介绍的很详细了

hdu1848 ( Fibonacci again and again )  sg函数与Nim博弈的组合

#include<iostream>
#include<algorithm>
using namespace std;
int fib[1010],a[20],hash1[1010],sg[1010];
void init()
{
    a[0]=a[1]=1;
    a[2]=2;
    memset(fib,0,sizeof(fib));
    fib[1]=fib[2]=1;
    for(int i=3;a[i-1]<=1000;i++)
    {
        a[i]=a[i-1]+a[i-2];
        fib[a[i]]=1;
    }
}
void Get_sg()
{
    for(int i=0;i<=3;i++)
        sg[i]=i;
    for(int i=4;i<=1000;i++)
    {
        memset(hash1,0,sizeof(hash1));
        for(int j=1;j<=i;j++)
            if(fib[j])
                hash1[sg[i-j]]=1;
        for(int k=0;k<=i;k++)
            if(!hash1[k])
            {
                sg[i]=k;
                break;
            }
    }
}
int main()
{
    init();
    Get_sg();
    int n,m,p;
    while(scanf("%d %d %d",&n,&m,&p)==3&& (m||n||p))
    {
        if((sg[n]^sg[m]^sg[p])!=0)
            puts("Fibo");
        else puts("Nacci");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/nanke/p/2245183.html