zoukankan      html  css  js  c++  java
  • 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".
    参看Sample Output.
     
    Sample Input
    2
    13
    10000
    0
     
    Sample Output
    Second win
    Second win First win
     

    Fibonacci 's Game   (斐波那契博弈)

    有一堆总数为n的石子,游戏双方轮流取石子,满足:
    1)先手不能在第一次就把所有的石子取完
    2)之后每次可以取的石子数介于1到对手取得石子数的两倍之间(包含1和对手刚取的石子数两倍)。
    和巴什博弈的不同点是-->巴什博弈取石子的策略是固定的,斐波那契博弈是依赖于前者取得石子数
     
    而斐波那契数列是解决斐波那契博弈的基础,所以斐波那契数列是什么咧?
    Fibonacci数列:f[n]:1,2,3,5,8,13,21,34,55,89……
     推理得出先手胜当且仅当n不是Fibonacci数。反面就是必败就是因为构成了Fibonacci数列
    哲学告诉我们,事物之间都是有联系的,所以要解决Fibonacci需要借助"Zeckendorf定理"(齐肯多夫定理)
    齐肯多夫定理告诉我们任何正整数都可以表示为若干个不连续的Fibonacci数之和
    举个例子
    比如肢解83(^_^),83介于55,89之间,于是可以携程83=55+28,28介于21,34之间,于是28=21+7, 7介于5,8之间,于是7=5+2;此时2,5,21,55都是Fibonacci数。
     
    来看看分解的伟大力量:若先手取2个,那么后手不可以取5个及其以上(2,5都是Fibonacc数),这样先手可以取到5颗石子的最后一颗,根据第二类归纳法,则先手可以取得21,55,的最后一颗,那么先手赢。
     如果n是Fibonacci数,例如89,设先手一开始取得数量为x个,如果x>=34(89前两项),那么后手一定赢,这是第一种情况,第二种,如果x<34,那么现在剩下的石子数y(89-x)介于55~89之间,也因此这个数一定不是Fibonacci数,所以要将它拆分,y=55+f[1],[2],f[i]……f[j],如f[j]<=2x;那么对后手就是面临y局面的先手,所以根据之前的分析,后手只要先取个f[j],即可,以后再按照之前的分析后手就赢啦
     
    综上所述:如果n是Fibonacci数,那么先手输,而巴什博弈就是判断n%(m+1)求余
     
     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int main(){
     4     int n,fib[50];
     5     fib[0]=2;fib[1]=3;//这里fib[0]就写了2是因为题目给的n是大于等于2的,所以省略了1这个fib数
     6     for(int i=2;i<50;i++)
     7         fib[i]=fib[i-1]+fib[i-2];
     8     while(cin>>n&&n){
     9     int i,flag=1;
    10     for(i=0;i<50;i++){
    11         if(fib[i]==n) flag=0,puts("Second win");
    12         if(fib[i]>n) break;
    13         }
    14         if(flag) puts("First win");  //处理完flag都没变,说明n不是Fibonacci数
    15     }
    16     return 0;
    17 }

    ps:摘录http://blog.csdn.net/wuff1988/article/details/9312559

    puts()函数只用来输出字符串,没有格式控制,里面的参数可以直接是字符串或者是存放字符串的字符数组名。

    printf()函数的输出格式很多,可以根据不同格式加转义字符,达到格式化输出。

    puts()函数的作用与语句printf("%s ",s);的作用形同。

     

    例子:

    #include   <stdio.h>  
       
      int   main(   void   )  
      {  
            puts(   "Hello   world   from   puts!"   );   //字符串,最后隐含带有''字符
      }  
      Output  
      Hello   world   from   puts!  

    main()
    {
        static char a[] = {'H','I','!','!'};
        puts(a);
    }
    则输出 Hi!!烫烫烫烫烫烫烫dhaklhdwuhdaghdagdak... (后面都是乱码)

    原因: a在结尾处缺少一个空字符(''), 所以它不是一个串,这样, puts() 就不知道什么时候停止输出, 它将会把 a 后面内存单元中的内容都打印出, 直到它在什么地方碰到了一个空字符为止

  • 相关阅读:
    Codeforces Round #394 (Div. 2) A. Dasha and Stairs
    HDU 1410 PK武林盟主
    HDU 3362 Fix(状压dp)
    P678-vect2.cpp
    Qt5获取本机网络信息
    Qt5标准文件对话框类
    nRF52832无法加载协议栈文件
    Debug记录(1)
    大小端模式
    nRF52832的SAADC
  • 原文地址:https://www.cnblogs.com/z-712/p/7307233.html
Copyright © 2011-2022 走看看