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 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 后面内存单元中的内容都打印出, 直到它在什么地方碰到了一个空字符为止