斐波那契博弈
(本文为笔者的个人学习笔记,如有不当之处恳请各位读者指正)
问题描述:有一堆个数为n的石子,游戏双方轮流取石子,满足:
(1)先手不能在第一次把所有的石子取完;
(2)之后每次可以取的石子数介于1到对手刚取的石子数的2倍之间(包含1和对手刚取的石子数的2倍)
解析:只需判断n是否为斐波那契数列中的数即可,若n为斐波那契数列中的数,则对于先手来说是必败局势。(注意前两项是1和2)。n为斐波那契数列中的数,
证明:当i=2时,先手只能取1个,后手取完剩余的1个,先手必败。
假设当i<=k时结论成立。设先手取走y个,后手取走x个。
则当i=k+1时,f(k+1)=f(k)+f(k-1),若先手第一次取的个数,则后手可以取走剩余的部分先手必败。
若先手第一次取的个数,则这堆中剩余的石子<2y,后手可以取完,后手取走,又因为, 所以。x最大达到 。 则对另一堆f(k):
则
所以,而所以,即。而此时先手可取的范围为 ,所以先手取不完剩余的那堆,先手必败。
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
int fib[50];
fib[0]=1;fib[1]=2;
for(int i=2;i<45;i++){
fib[i]=fib[i-1]+fib[i-2];//构造斐波那契数列
}
while(1){
int n;
cin>>n;
if(n==0)
break;
int i;
for(i=0;i<45;i++){
if(fib[i]==n)//n是否为斐波那契数
break;
}
if(i<45)
cout<<"Second win"<<endl;//先手面临斐波那契堆,后手赢
else
cout<<"First win"<<endl;//先手面临的不是斐波那契堆,先手赢
}
}
import java.util.*; public class FibonaccisGame { public static void main(String[] args) { Scanner sc=new Scanner(System.in); int fib[]=new int[50]; fib[0]=1;fib[1]=2; for(int i=2;i<45;i++){ fib[i]=fib[i-1]+fib[i-2];//构造斐波那契数列 } while(true){ int n=sc.nextInt(); if(n==0) break; int i; for(i=0;i<45;i++){ if(fib[i]==n)//判断n是否为斐波那契数 break; } if(i<45) System.out.println("Second win");//先手面临斐波那契堆,后手赢 else System.out.println("First win");//先手面临的不是斐波那契堆,先手赢 } } }