2.从第二次开始,每个人取的石子数至少为1,至多为对手刚取的石子数的两倍。
himdd事先想知道自己会不会赢,你能帮帮他吗?(每次himdd先手)
2 5 6
No No Yes
思路:
结论:当n为fibonacci数时,先手必败(n >= 2);
证明:
以下为个人思路:
根据“Zeckendorf定理”(齐肯多夫定理):任何正整数可以表示为若干个不连续的Fibonacci数之和(优先选取最大的)。
比如 n = 14 时, n = 8 + 5 + 1;而先手要赢的条件是,先手必须要先取完最小的一堆,再取完次小的一堆,以此类推,并保证每堆的最后一个是自己取到的而且不能取超!听起来有点绕,举个例子:
先看必胜态,n不是fibonacci数的时候,令n = 9 =5 + 3 + 1:
a、先手先取最小的一堆,1个,保证了最后一个是自己取得;
b、此时后手开始取次小的一堆(3个石子),上面说过,要想赢的话,要保证这一堆的第3个必须是自己取得;此时后手有 1、2两种取法,但此处无论后手怎么取,都能
保证这一堆的最后一个(第3个)是自己取得;
c、此时后手开始取最后一堆(5个石子),b步先手可能取得是1或2,因此此步后手可能有1、2、3、4四种取法,易知后手取3或4的话,自己立马就能取到最后一个,就
赢了,而取1或2时,同上(读者自己来),仍能保证取到最后一个(此堆第5个,全局最后一个),必赢!
再说必败态,若n是fibonacci数时,为方便观察,令n=5:
fib[i] = fib[i-1] + fib[i - 2]; 即 5 = 3 + 2;实际上与上面相反,无论自己怎么取,后手都能保证自己取到最小一堆的最后一个,因此后手必胜!
代码:
#include <stdio.h> #define N 100 long long fib[N]; void Fib() { fib[0] = 0; fib[1] = 1; for(int i = 2; i < N; i ++){ fib[i] = fib[i - 1] + fib[i - 2]; } } int main() { Fib(); long long n; while(scanf("%lld", &n) != EOF){ bool is_fib = 0; for(int i = 2; i < 100; i ++){ if(fib[i] == n){ is_fib = 1; break; } } if(is_fib) printf("No\n"); else printf("Yes\n"); } return 0; }
nyoj-358 取石子(五)(斐波那契博弈),布布扣,bubuko.com
原文:http://blog.csdn.net/tbl_123/article/details/24033245