博弈论习题

poj2234

真。裸题。

#include<cstdio>
#include<cstring>
#include<algorithm>
using  namespace std;
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        int ans=0,s;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&s);
            ans^=s;
        }
        if(ans==0)
            printf("No\n");
        else printf("Yes\n");
    }
}

Hdu2176
一看知道是尼姆博弈,暴力做,TLE了,在这里记一下,有个好神奇的东西,一个数n和m异或之后再和m异或会重新变成n。还是太菜了,看了尼姆博弈,但是过程也看的不是特别细,第一次取石子还是没理解透彻。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[200005];
int main()
{
    int n;
    while(~scanf("%d",&n)&&n)
    {
        int t=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            t=t^a[i];
        }
        if(t==0)
            printf("No\n");
        else {
            int temp;
            printf("Yes\n");
            for(int i=0;i<n;i++)
            {
                temp=t^a[i];
                if((temp^t^a[i])==0)
                {
                    if((t^a[i])<a[i])
                    printf("%d %d\n",a[i],t^a[i]);
                }
            }
        }

    }

}

poj2975
和上面的题差不多,也是求第一步能有几种走法,把上面那个改一改就差不多了。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[1005];
int main()
{
    int t;
    while(~scanf("%d",&t)&&t)
    {
        int ans=0;
        for(int i=0; i<t; i++)
        {
            scanf("%d",&a[i]);
            ans^=a[i];
        }
        int sum=0;
        if(ans==0)
        {
            printf("0\n");
            continue;
        }
        else
        {
            int temp;
            for(int i=0; i<t; i++)
            {
                temp=ans^a[i];
                if((temp^ans^a[i])==0&&(ans^a[i])<a[i])
                {
                    sum++;
                }
            }
        }
        printf("%d\n",sum);
    }
}

Hdu1730
没什么好说的,裸地尼姆博弈

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int a[1005];
int main()
{
    int n,m;
    while(~scanf("%d %d",&n,&m))
    {
        int aa,b,t=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d %d",&aa,&b);
            a[i]=max(aa,b)-min(aa,b)-1;
            t=t^a[i];
        }
        if(t==0)
            printf("BAD LUCK!\n");
        else printf("I WIN!\n");
    }
}

poj2960
比较经典的SG函数的题吧,一直WA。。。原因是求SG值的地方错了(虽然我也不知道哪里错了)蓝瘦。。。。。
题意比较明显,就是告诉你一个集合S,只能拿这个集合里有的数,有n个例子,每个例子有m堆,把这m堆分解成m个子游戏,分别求SG值,然后再异或,得到答案是0就输出L不然就输出W(注意他是n个例子每个例子下面就是输出不要攒到一起输出,我就被样例给骗了。)还是自己太弱了吧。继续加油。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int s[105],d,dp[10005],t[105];
bool vis[10005];
const int temp =10005;
int main()
{
    int n,m,k;
    while(~scanf("%d",&n)&&n)
    {
        memset(dp,0,sizeof dp);
        memset(vis,0,sizeof vis);
        memset(s,0,sizeof s);
        memset(t,0,sizeof t);
        for(int i=0; i<n; i++)
            scanf("%d",&s[i]);
        sort(s,s+n);
        dp[0]=0;
        for(int i=1; i<temp; i++)
        {
            memset(vis,0,sizeof vis);
            for(int j=0; j<n; j++)
            {
                if(i-s[j]>=0)
                    vis[dp[i-s[j]]]=1;
                else break;
            }
            for(int j=0;; j++)
            {
                if(!vis[j])
                {
                    dp[i]=j;
                    break;
                }
            }
        }
        scanf("%d",&m);
        int mount=0;
        for(int i=0; i<m; i++)
        {
            scanf("%d",&k);
            int ans=0;
            for(int j=0; j<k; j++)
            {
                scanf("%d",&d);
                ans=ans^(dp[d]);
            }
            if(ans==0)
            {
                printf("L");
            }
            else printf("W");
        }
        printf("\n");
    }
}

网上都是非常简短的函数,我写的有些丑。

poj1067
威佐夫博弈的裸题。给你x,y,如果x>y,交换。z=y-x。
然后w=(int)(((sqrt(5.0)+1)/2)*z)
然后判断w和x相不相等。相等就是先手必败,否则就是必胜。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int main()
{
    int n,m;
    while(~scanf("%d %d",&n,&m))
    {
        int x=min(n,m);
        int y=max(n,m);
        int z=y-x;
        int w=(int)(((sqrt(5.0)+1)/2)*z);
        if(w==x)
            printf("0\n");
        else printf("1\n");
    }
}

poj2425
开始读题一直没读懂。搞样例搞了好久。。。。
大概就是给你一个图,然后告诉你上面那几个点上有棋子,然后双方轮流走谁先无棋可走谁就输了。和SG函数的定义很像。因为一些细节一直做不出来。。。。建图建的不好,想省事顺便练练存图,用vector结果初始化-1卡住了,又改回二维数组。费了老大功夫。。以后看数据量不大还是用二维数组吧。。。。
修改:再次看自己写的是个**。
有一个有向图,建好图之后某些点上会有石子,根据图可以求出对应点的SG值,然后求异或和。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int adj[1050][1050];
int sg[1005];
int n;
int serch(int n1)
{
    bool vis[1005];
    if(sg[n1]!=-1)
        return sg[n1];
    memset(vis,0,sizeof vis);
    for(int i=0; i<n; i++)
    {
        if(adj[n1][i]!=-1)
        {
            vis[serch(i)]=1;
        }

    }
    int w=0;
    while(vis[w])w++;
    return sg[n1]=w;

}
int main()
{
    while(~scanf("%d",&n))
    {
        memset(sg,-1,sizeof sg);
        memset(adj,-1,sizeof adj);
        for(int i=0; i<n; i++)
        {
            int m,t;
            scanf("%d",&m);
            if(m==0)
            {
                sg[i]=0;
            }
            for(int j=0; j<m; j++)
            {
                scanf("%d",&t);
                adj[i][t]=1;
            }
        }
        int m;
        while(~scanf("%d",&m)&&m)
        {
            int x;
            int ans=0;
            for(int i=0; i<m; i++)
            {
                scanf("%d",&x);
                ans^=serch(x);
            }
            if(ans==0)
                printf("LOSE\n");
            else printf("WIN\n");
        }
    }

}

poj1704
做过一次的,还错了。。。
题意是一行棋盘上有一堆棋子,然后轮流向左移。谁先无法移动谁输。
将两个棋子之间的格子数目看做一堆棋子,如果总棋子数是奇数,就把第一个和边界之间的格子数目看成一堆棋子(注意,奇数)然后nim博弈。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int main()
{
    int p[1000];
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        memset(p,0,sizeof p);
        scanf("%d",&n);
        int mount=0;
        if(n%2==1)
            p[mount++]=0;
        for(int i=0; i<n; i++)
        {
            int a;
            scanf("%d",&a);
            p[mount++]=a;
        }
        sort(p,p+mount);
        int x=0;
        for(int i=0; i+1<mount; i+=2)
        {
            x^=(p[i+1]-p[i]-1);
        }
        if(x==0)
            printf("Bob will win\n");
        else puts("Georgia will win");
    }

}

poj1740
没做出来,看的题解。。。
大概就是偶数的时候如果排序之后的12、34…..都相等的话,无论先手怎么走后手模仿先手必败。其他就是先手必胜
而奇数先手只要把最大的拿走然后创造一个12 34 ….都相等的局面就好了。先手必胜。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[1005];
int main()
{
    int n;
    while(~scanf("%d",&n)&&n)
    {
        memset(a,0,sizeof a);
        for(int i=0; i<n; i++)
            scanf("%d",&a[i]);
            int flag=0;
        if(n%2==1)
        {
            printf("1\n");
            continue;
        }
        else {
                sort(a,a+n);
            for(int i=0;i<n;i+=2)
            {
                if(a[i]!=a[i+1])
                {
                    flag=1;
                }
            }
        }
        printf("%d\n",flag);

    }
}

poj2068
看着网上的一堆题解发憷,都是当水题来做,蓝瘦。
dp[i][j]表示第i个人时候还有j个石子,然后当j=0时为1;
后继里面有存在0的这个状态就是1;

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[30],dp[30][8200];
int n,s;
int slove(int x,int S)
{
    if(dp[x][S]!=-1)return dp[x][S];
    for(int i=1; i<=a[x]; i++)
    {
        int t=S-i;
        if(t<0)
            break;
        int y;
        if(x+1>=2*n)y=0;
        else y=x+1;
        if(slove(y,t)==0)return dp[x][S]=1;
    }
    return dp[x][S]=0;
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        memset(a,0,sizeof a);
        scanf("%d",&s);
        for(int i=0; i<2*n; i++)
            scanf("%d",&a[i]);
        memset(dp,-1,sizeof dp);
        for(int i=0; i<2*n; i++)
            dp[i][0]=1;
        int ans=slove(0,s);
        if(ans==0)
            printf("0\n");
        else printf("1\n");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值