zoukankan      html  css  js  c++  java
  • *HDU1848 博弈

    Fibonacci again and again

    Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 8074    Accepted Submission(s): 3357


    Problem 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
     
    Author

    lcy

    于nim游戏的某个位置(x1,x2,x3),当且仅当它各部分的nim-sum等于0时(即x1⊕x2⊕x3=0),则当前位于必败点

    这道题用到了上面那个定理,有3堆,每次只能从每堆那里移除斐波那契数的石子。由于每堆有不同的取法,所以把可能出现同种情况的数字归为一类。称为等价类。每一个类又对应一个数叫做等价类数

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

    等价类数 E[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

    e[1]=1; 

    例如 i=2,

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

    e[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

    e[3]=3;

    例如 i=4

    取走fib[1,2,3]=1,2,3个 剩下3,2,1,没有出现的最小数就是0

    e[4]=0;   4是必败点

    例如 i=5

    取走fib[1,2,3,4]=1,2,3,5个 剩下4,3,2,0,等价类数是 0,3,2,0没有出现的最小数就是1(e(4)=0)

    e[5]=1;

    例如 i=6

    取走fib[1,2,3,4]=1,2,3,5个 剩下5,4,3,1,等价类数是e[5],e[4],e[3],e[1],即1,0,3,1,没有出现的最小的是2  e[6]=2;

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

    代码:

     1 #include<iostream>
     2 #include<cstring>
     3 using namespace std;
     4 int main()
     5 {
     6     int a,b,c,f[502],e[1003],m[1003];
     7     f[0]=1;f[1]=1;
     8     e[0]=0;e[1]=1;e[2]=2;e[3]=3;
     9     for(int i=2;i<=500;i++)
    10         f[i]=f[i-1]+f[i-2];
    11     for(int i=4;i<=1000;i++)
    12     {
    13         memset(m,0,sizeof(m));
    14         for(int j=1;f[j]<=i;j++)
    15         {
    16             m[e[i-f[j]]]=1;
    17         }
    18         for(int j=0;j<=i+1;j++)
    19             if(m[j]==0)
    20             {e[i]=j;break;}
    21     }
    22     while(cin>>a>>b>>c,a,b,c)
    23     {
    24         if(e[a]^e[b]^e[c]) cout<<"Fibo
    ";
    25         else cout<<"Nacci
    ";
    26     }
    27     return 0;
    28 }
  • 相关阅读:
    遂宁2017届零诊16题(仅想说明网传答案的不正确)
    当参变分离遇见洛必达
    高考数学九大超纲内容(1)wffc
    给王志红老师构造的函数,想说明搜题软件的解答过程的不严谨!
    记住路径名
    php返回文件路径
    两个字符串合并为一个字符串的各种方法
    global作用域
    二进制字符串的比较
    var_dump — 打印变量的相关信息
  • 原文地址:https://www.cnblogs.com/--ZHIYUAN/p/6163639.html
Copyright © 2011-2022 走看看