码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2017-08-15 21:16:15      阅读:202      评论:0      收藏:0      [点我收藏+]

标签:otto   world   ret   tps   开始   input   tail   策略   ros   

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\n",s);的作用形同。

 

例子:

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

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

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

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

标签:otto   world   ret   tps   开始   input   tail   策略   ros   

原文地址:http://www.cnblogs.com/z-712/p/7307233.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!