zoukankan      html  css  js  c++  java
  • hduoj 1848 Fibonacci again and again【sg函数】【博弈】【菲波那切数列】

    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
    ");
    39         else
    40             printf("Nacci
    ");    
    41     }
    42     return 0;
    43 }
  • 相关阅读:
    栏目调用 sql语句
    一场豪赌 微软的未来取决于Windows 8
    mark
    [导入].net中的如何私有部署强命名组件
    q160问题,www.q160.com,ie被篡改
    解决jdgui保存源码自动添加注释的情况
    汉诺塔问题
    软件测试 方法总结
    javascript 基础篇4 window对象,DOM
    javascript 进阶篇1 正则表达式,cookie管理,userData
  • 原文地址:https://www.cnblogs.com/123tang/p/5979403.html
Copyright © 2011-2022 走看看