HDU-1848 Fibonacci again and again(组合游戏)

题目链接

HDU-1848 Fibonacci again and again

题目大意

3 堆石子,分别有m,n,p个,两人轮流进行取石子,每次可以从一堆石子取走任意正整数个石子,最先取光石子的一方为胜,判断先手是否必胜?

Sample Input

1 1 1
1 4 1
0 0 0

Sample Output

Fibo
Nacci

思路

这篇博文通过实例很清楚的介绍了基础的 SG 求法(可能是没看到别的吧。。。),感觉已经明白了 SG 的定义和计算方法。

设运算 mex(minimalexcludant) 是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。
若状态 S 能到达状态a,b,c,则 mex(S)=mex{SG[a],SG[b],SG[c]}

SG 性质:
①对于任意的局面,如果它的 SG 值为 0 ,那么它的任何一个后继局面的SG值不为 0
②对于任意的局面,如果它的SG值不为 0 ,那么它一定有一个后继局面的SG值为 0

SG
在我们每次只能进行一步操作的情况下,对于任何的游戏的和,我们若将其中的任一单一 SG 换成数目为它的 SG 值的一堆石子,该单一 SG 的规则变成取石子游戏的规则(可以任意取,甚至取完),则游戏的和的胜负情况不变。

实际运用起来就是将组合游戏看成尼姆博弈,将所有的 SG 值异或起来判断组合游戏的胜负。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int n,m,p,ans;
int f[55],cnt,sg[1005];
bool vis[1005];

void init() {
    f[1]=f[2]=1;
    cnt=2;
    while(f[cnt]<1000) {
        f[cnt+1]=f[cnt]+f[cnt-1];
        ++cnt;
    }
}

void getSG(int mx) {
    sg[0]=0;
    for(int i=1;i<=mx;++i) {
        memset(vis,false,sizeof(vis));
        for(int j=1;f[j]<=i;++j) {
            vis[sg[i-f[j]]]=1;
        }
        for(int j=0;j<=i;++j) {
            if(!vis[j]) {
                sg[i]=j;
                break;
            }
        }
    }
}

int main() {
    init();
    getSG(1000);
    while(scanf("%d%d%d",&m,&n,&p),m!=0||n!=0||p!=0) {
        printf("%s\n",(sg[m]^sg[n]^sg[p])==0?"Nacci":"Fibo");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值