hduoj 1848 Fibonacci again and againsg函数博弈菲波那切数列

Posted 唐唐123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hduoj 1848 Fibonacci again and againsg函数博弈菲波那切数列相关的知识,希望对你有一定的参考价值。

Fibonacci again and again

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函数http://baike.so.com/doc/6839718-7056990.html

等价类数的算法(0其实就是必败的点,对于一堆来说)

sg[0]=0;

等价类数 sg[i] 的算法:

从i个中取走 fib[1],fib[2],...,fib[j]<=i 个后剩下i-fib[1], i-fib[2],..., i-fib[j]个
他们的等价类数中没有出现的最小数就是i的等价类数

例如 i=1,
取走fib[1]=1个 i-fib[1]=0,0的等价类数是0,没有出现的最小数就是1
sg[1]=1;

例如 i=2,
取走fib[1]=1个 i-fib[1]=1,取走fib[2]=2个 i-fib[1]=0,
1和0的等价类数是1,0,没有出现的最小数就是2
sg[2]=2;

例如 i=3
取走fib[1]=1个 i-fib[1]=2,取走fib[2]=2个 i-fib[1]=1,取走fib[3]=3个 i-fib[1]=0,
2,1和0的等价类数是2,1,0,没有出现的最小数就是3
sg[3]=3;

例如 i=4
取走fib[1,2,3]=1,2,3个 剩下3,2,1,没有出现的最小数就是0
sg[4]=0; 4是必败点

例如 i=5
取走fib[1,2,3,4]=1,2,3,5个 剩下4,3,2,0,等价类数是 0,3,2,0没有出现的最小数就是1
sg[5]=1;

这样就得到了一个等价类数数组。接着就运用那个定理,如果一开始就出现必败点,即(sg[n] ^ sg[m] ^ e[p]) == 0。那么按照最优走法则必输。其它情况必赢。


AC代码
 1 #include<cstdio>
 2 #define maxn 1005
 3 int m, n, p, sg[maxn], hash[21];
 4 int f[16]={1,1,2};
 5 int fibonacci()
 6 {
 7     for(int i = 3; i <= 16; i++)
 8         f[i] = f[i-1] + f[i-2];
 9 }
10 void getsg()
11 {
12     int i, j;
13     sg[0] = 0; sg[1] = 1;
14     for(i = 2; i <= maxn; i++)
15     {
16         for(j = 0; j <= 20; j++)
17             hash[j] = 0;
18         
19         //寻找等价类数 
20         for(j = 1; f[j] <= i; j++)
21             hash[sg[i-f[j]]] = 1;
22         for(j = 0; j <= 20; j++)
23         {
24             if(!hash[j])
25             { sg[i] = j; break;    }
26         }
27     }
28 }
29 int main()
30 {
31     fibonacci();
32     getsg();
33     while(scanf("%d %d %d", &m, &n, &p))
34     {
35         if(m + n + p == 0)
36             break;
37         if(sg[n]^sg[m]^sg[p])
38             printf("Fibo\n");
39         else
40             printf("Nacci\n");    
41     }
42     return 0;
43 }

以上是关于hduoj 1848 Fibonacci again and againsg函数博弈菲波那切数列的主要内容,如果未能解决你的问题,请参考以下文章

HDU1848 Fibonacci again and again

HDU 1848 Fibonacci again and again

HDU1848 Fibonacci again and again(SG函数)

hdu 1848 Fibonacci again and again(SG函数)

HDU 1848(sg博弈) Fibonacci again and again

hdu 1848 Fibonacci again and again(简单sg)