取石子游戏与SG函数

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1848


题意:有3堆石子,石子数量分别为a,b,c,有两个玩家,每次只能从任意一堆中取f个,这里的f只能为fibnacci数,问是先手

还是先手败.


分析:由于石子的数量都在1000以内,那么我们可以先预处理出1000以内的SG函数值,然后对于3堆石子,我们进行异或,如果为

0说明先手必败,否则必胜,当然求SG函数的值用深搜就行了.


#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;
const int N = 1005;
const int M = 25;

int fib[25];
int SG[N];

int mex(int x)
{
    bool vis[M];
    memset(vis,0,sizeof(vis));
    for(int i=0;i<M;i++)
    {
        int t = x - fib[i];
        if(t < 0) break;
        if(SG[t] == -1)
            SG[t] = mex(t);
        vis[SG[t]] = 1;
    }
    for(int i=0;;i++)
    if(!vis[i]) return i;
}

void Init()
{
    fib[0] = 1;
    fib[1] = 2;
    for(int i=2;i<M;i++)
        fib[i] = fib[i-1] + fib[i-2];
    memset(SG,-1,sizeof(SG));
    for(int i=0;i<N;i++)
        SG[i] = mex(i);
}

int main()
{
    Init();
    int a,b,c;
    while(~scanf("%d%d%d",&a,&b,&c))
    {
        if(a == 0 && b == 0 && c == 0) break;
        int ans = 0;
        ans ^= SG[a];
        ans ^= SG[b];
        ans ^= SG[c];
        if(ans) puts("Fibo");
        else    puts("Nacci");
    }
    return 0;
}


题目:http://acm.hdu.edu.cn/showproblem.php?pid=1536


分析:本题基本上跟上体一样,只是把3堆改为x堆,把取fibnacci数列颗石子改为取指定输入的石子个数.那么做法实际上一

样,我们对输入的序列进行排序,然后求出它们的SG函数的值,然后直接用即可.


#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>

using namespace std;
const int N = 10005;
const int M = 105;

int a[M];
int SG[N];
int n;

int mex(int x)
{
    bool vis[M];
    memset(vis,0,sizeof(vis));
    for(int i=0;i<n;i++)
    {
        int t = x - a[i];
        if(t < 0) break;
        if(SG[t] == -1)
            SG[t] = mex(t);
        vis[SG[t]] = 1;
    }
    for(int i=0;;i++)
    if(!vis[i]) return i;
}

int main()
{
    while(~scanf("%d",&n))
    {
        if(n == 0) break;
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        sort(a,a+n);
        memset(SG,-1,sizeof(SG));
        for(int i=0;i<N;i++)
            SG[i] = mex(i);
        int m;
        scanf("%d",&m);
        while(m--)
        {
            int ans = 0;
            int len,t;
            scanf("%d",&len);
            for(int i=0;i<len;i++)
            {
                scanf("%d",&t);
                ans ^= SG[t];
            }
            if(ans) printf("W");
            else    printf("L");
        }
        puts("");
    }
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值