HDU 1848 Fibonacci again and again (斐波那契博弈SG函数)

Fibonacci again and again

Time Limit: 1000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u

Submit Status

Description

任何一个大学生对菲波那契数列(Fibonacci numbers)应该都不会陌生,它是这样定义的: 
F(1)=1; 
F(2)=2; 
F(n)=F(n-1)+F(n-2)(n>=3); 
所以,1,2,3,5,8,13……就是菲波那契数列。 
在HDOJ上有不少相关的题目,比如1005 Fibonacci again就是曾经的浙江省赛题。 
今天,又一个关于Fibonacci的题目出现了,它是一个小游戏,定义如下: 
1、  这是一个二人游戏; 
2、  一共有3堆石子,数量分别是m, n, p个; 
3、  两人轮流走; 
4、  每走一步可以选择任意一堆石子,然后取走f个; 
5、  f只能是菲波那契数列中的元素(即每次只能取1,2,3,5,8…等数量); 
6、  最先取光所有石子的人为胜者;

假设双方都使用最优策略,请判断先手的人会赢还是后手的人会赢。

Input

输入数据包含多个测试用例,每个测试用例占一行,包含3个整数m,n,p(1<=m,n,p<=1000)。 
m=n=p=0则表示输入结束。

Output

如果先手的人能赢,请输出“Fibo”,否则请输出“Nacci”,每个实例的输出占一行。

Sample Input

1 1 1
1 4 1
0 0 0

Sample Output

Fibo
Nacci

题意如题。

题解:求sg值即可,因为i的后继都是小于i的,即i的后继的sg值已知,所以可以不搜索,给出两种AC代码。

利用dfs求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;
}  

非深搜:

#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];
void get()
{
    bool vis[M];
    for(int i=0;i<N;i++) //sg数组
    {
        memset(vis,0,sizeof(vis));
        for(int j=0;j<M&&fib[j]<=i;j++) //要用的s数组  注意这里有等号
        {
            vis[SG[i-fib[j]]]=1;
        }
        for(int x=0;x<N;x++)
            if(!vis[x])
        {
            SG[i]=x;
            break;
        }
    }

}
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,0,sizeof(SG)); //这里定义成 -1和0都可以
        get();
}

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;
}
时间: 2024-12-24 14:39:36

HDU 1848 Fibonacci again and again (斐波那契博弈SG函数)的相关文章

HDU 2516 取石子游戏 (斐波那契博弈)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2516 1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍.取完者胜.先取者负输出"Second win".先取者胜输出"First win". Input输入有多组.每组第1行是2<=n<2^31. n=0退出. Output先取者负输出"Second win". 先取者胜输

题解报告:hdu 2516 取石子游戏(斐波那契博弈)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2516 Problem Description 1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍.取完者胜.先取者负输出"Second win".先取者胜输出"First win". Input 输入有多组.每组第1行是2<=n<2^31. n=0退出. Output 先取者负输出"S

hdoj 2516 取石子游戏(斐波那契博弈)

Problem Description 1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍.取完者胜.先取者负输出"Second win".先取者胜输出"First win". Input 输入有多组.每组第1行是2<=n<2^31. n=0退出. Output 先取者负输出"Second win". 先取者胜输出"First win". 参看Samp

hdu 1316 How many Fibs?(高精度斐波那契数)

//  大数继续 Problem Description Recall the definition of the Fibonacci numbers: f1 := 1 f2 := 2 fn := fn-1 + fn-2 (n >= 3) Given two numbers a and b, calculate how many Fibonacci numbers are in the range [a, b]. Input The input contains several test cas

HDU 4639 Hehe(字符串处理,斐波纳契数列,找规律)

题目 //每次for循环的时候总是会忘记最后一段,真是白痴.... //连续的he的个数 种数 //0 1 //1 1 //2 2 //3 3 //4 5 //5 8 //…… …… //斐波纳契数列 //不连续的就用相乘(组合数)好了 #include<iostream> #include<algorithm> #include<string> #include <stdio.h> #include <string.h> #include &l

HDU 2516 取石子游戏 斐波纳契博弈

斐波纳契博弈: 有一堆个数为n的石子,游戏双方轮流取石子,满足: 1)先手不能在第一次把所有的石子取完: 2)之后每次可以取的石子数介于1到对手刚取的石子数的2倍之间(包含1和对手刚取的石子数的2倍). 约定取走最后一个石子的人为赢家,求必败态. 证明 FBI数为必败局: 1.对于任意一个FBI数 FBI[K]=FBI[K-1]+FBI[K-2],我们可以将FBI[K]看成石子数目分别是FBI[K-1],FBI[K-2]的两堆(一定可以这样分,因为FBI[K-1] > FBI[K-2]*2,若先

2.斐波那契博弈

HDU2516  http://acm.hdu.edu.cn/showproblem.php?pid=2516 这次咱们是先看的题目,没错,这个水题没有任何技术含量滴,运用的就是斐波那契博弈. 下面说一下另一种博弈哈,斐波那契博弈,小伙伴们疑惑啦,不是有斐波那契数列嘛,怎么又来一个斐波那契博弈,没错!嘿嘿,他俩是一样一样滴,就是运用斐波那契数列的知识,不过上代码之前,咱们先看看原理.. 转载的: n = 2时输出second:      n = 3时也是输出second:  n = 4时,第一个

51nod Bash游戏(V1,V2,V3,V4(斐波那契博弈))

Bash游戏V1 有一堆石子共有N个.A B两个人轮流拿,A先拿.每次最少拿1颗,最多拿K颗,拿到最后1颗石子的人获胜.假设A B都非常聪明,拿石子的过程中不会出现失误.给出N和K,问最后谁能赢得比赛. 例如N = 3,K = 2.无论A如何拿,B都可以拿到最后1颗石子. Input 第1行:一个数T,表示后面用作输入测试的数的数量.(1 <= T <= 10000) 第2 - T + 1行:每行2个数N,K.中间用空格分隔.(1 <= N,K <= 10^9) Output 共T

博弈论入门之斐波那契博弈

斐波那契博弈 斐波那契博弈是一种经典的博弈问题 有一堆石子,两个顶尖聪明的人玩游戏,先取者可以取走任意多个,但不能全取完,以后每人取的石子数不能超过上个人的两倍 结论 斐波那契博弈有一个非常重要的性质: 先手必败,当且仅当石子数为斐波那契数 是不是很神奇?? 证明: 懒得看了,这里有 代码 HDU 2516 #include<cstdio> #include<map> int fib[233],x; std::map<int,bool>mp; int main() {