Description
Input
Output
Sample Input
2 13 10000 0
Sample Output
Second win Second win First win
、
又是取石子游戏,不过这次的和之前的可不一样了。好像是FIB博弈(感觉数学的的定理公式怎么就这么多呢。。。。无奈)
转载于:http://yjq24.blogbus.com/logs/46150651.html
有一堆个数为n的石子,游戏双方轮流取石子,满足:
1)先手不能在第一次把所有的石子取完;
2)之后每次可以取的石子数介于1到对手刚取的石子数的2倍之间(包含1和对手刚取的石子数的2倍)。
约定取走最后一个石子的人为赢家,求必败态。
这个和之前的Wythoff’s Game 和取石子游戏 有一个很大的不同点,就是游戏规则的动态化。之前的规则中,每次可以取的石子的策略集合是基本固定的,但是这次有规则2:一方每次可以取的石子数依赖于对手刚才取的石子数。
这个游戏叫做Fibonacci Nim,肯定和Fibonacci数列:f[n]:1,2,3,5,8,13,21,34,55,89,… 有密切的关系。如果试验一番之后,可以猜测:先手胜当且仅当n不是Fibonacci数。换句话说,必败态构成Fibonacci数列。
就像“Wythoff博弈”需要“Beatty定理”来帮忙一样,这里需要借助“Zeckendorf定理”(齐肯多夫定理):任何正整数可以表示为若干个不连续的Fibonacci数之和。定理的证明可以在 这里 看到,不过我觉得更重要的是自己动手分解一下。
比如,我们要分解83,注意到83被夹在55和89之间,于是把83可以写成83=55+28;然后再想办法分解28,28被夹在21和34之间,于是28=21+7;依此类推 7=5+2,故 ;
如果n=83,我们看看这个分解有什么指导意义:假如先手取2颗,那么后手无法取5颗或更多,而5是一个Fibonacci数,如果猜测正确的话,(面临这5颗的先手实际上是整个游戏的后手)那么一定是先手取走这5颗石子中的最后一颗,而这个我们可以通过第二类归纳法来绕过,同样的道理,接下去先手取走接下来的后21颗中的最后一颗,再取走后55颗中的最后一颗,那么先手赢。
反过来如果n是Fibonacci数,比如n=89:记先手一开始所取的石子数为y,若y>=34颗(也就是89的向前两项),那么一定后手赢,因为89-34=55=34+21<2*34,所以只需要考虑先手第一次取得石子数y<34的情况即可,所以现在剩下的石子数x介于55到89之间,它一定不是一个Fibonacci数,于是我们把x分解成Fibonacci数:x=55+f[i]+…+f[j],若,如果f[j]<=2y,那么对B就是面临x局面的先手,所以根据之前的分析,B只要先取f[j]个即可,以后再按之前的分析就可保证必胜。
下证:f[j]<=2y
反证法:假设f[j]>2y,则 y < f[j]/2 = (f[j-1] + f[j-2])/2 < f[j-1]
而最初的石子数是个斐波那契数,即 f[k]=x+y < f[k-1]+f[i]+…+f[j]+f[j-1] <= f[k-1]+f[i]+f[i-1] <= f[k-1]+f[k-2] <= f[k] (注意第一个不等号是严格的,矛盾!)
ps:这个博弈还是第一次见,不过我觉得做博弈,重要的是能根据已知情况,猜测出未知的情况,这就是规律!
转载请注明出处:寻找&星空の孩子
//FIB博弈,找规律 //定理证明:http://yjq24.blogbus.com/logs/46150651.html #include<stdio.h> #define LL long long #define MM 0x7FFFFFFF LL len,Fib[100000]; void init() { len=3; Fib[1]=1; Fib[2]=2; for(;;len++) { Fib[len]=Fib[len-1]+Fib[len-2]; if(Fib[len]>(1LL<<31)) break; } } int main() { init(); LL n; // printf("len=%lld,%lld\n",len,Fib[46]); while(scanf("%lld",&n),n) { if(n==3||n==2) { printf("Second win\n");continue;} LL t=3; bool bo=true; while(t<=len) { if(n==Fib[t]){bo=false;printf("Second win\n");break;} if(Fib[t]>n) break; t++; } if(bo) printf("First win\n"); } return 0; }