斐波那契游戏 解题报告

【博弈】斐波那契游戏

Time Limit:1000MS  Memory Limit:65536K

Description

任何一个大学生对菲波那契数列(Fibonacci numbers)应该都不会陌生,它是这样定义的:
F(1)=1;
F(2)=2;
F(n)=F(n-1)+F(n-2)(n>=3);
所以,1,2,3,5,8,13……就是菲波那契数列。
在HDOJ上有不少相关的题目,比如1005 Fibonacci again就是曾经的浙江省赛题。
今天,又一个关于Fibonacci的题目出现了,它是一个小游戏,定义如下:
1、这是一个二人游戏;
2、一共有3堆石子,数量分别是m, n, p个;
3、两人轮流走;
4、每走一步可以选择任意一堆石子,然后取走f个;
5、f只能是菲波那契数列中的元素(即每次只能取1,2,3,5,8…等数量);
6、最先取光所有石子的人为胜者。

假设双方都使用最优策略,请判断先手的人会赢还是后手的人会赢。

Input

输入数据包含多个测试用例,每个测试用例占一行,包含3个整数m,n,p(1<=m,n,p<=1000)。
m=n=p=0则表示输入结束。

Output

如果先手的人能赢,请输出“Fibo”,否则请输出“Nacci”,每个实例的输出占一行。

Sample Input

1 1 1
1 4 1
0 0 0

Sample Output

Fibo

Nacci


这一题有点像Nim游戏,可是和Nim游戏又好像完全不一样啊!

因为它限制了每次可以取的石子数,这时就必须用上SG定理了。http://blog.csdn.net/weixin_39872717/article/details/79025251

那么这一题的各个状态的SG值是什么?因为每次可以取走斐波那契数列里的数的石子数,那么对于任意状态i,i-Fibonacci[j]都是可以取到的,故我们需要预处理出Fibonacci数列,然后通过枚举的方法,把i-Fibonacci[j]的SG值全部标记,扫一遍,找到最小的非负整数即为i的SG值。

代码:

#include
#include
using namespace std;
	int a,b,c;
	int sg[1001];
	int fibonacci[21];
	bool visited[11];
void first() //预处理出所有SG值
{
	fibonacci[1]=1;
	fibonacci[2]=2;
	for (int i=3;i<=20;i++) //先预处理出Fibonacci数列,因为m,n,p<=1000,我们只要预处理到1000附近即可
		fibonacci[i]=fibonacci[i-1]+fibonacci[i-2];
	for (int i=1;i<=1000;i++)
	{
		memset(visited,false,sizeof(visited)); //visited数组记录所有出现过的非负整数
		for (int j=1;j<=20;j++)
			if (fibonacci[j]<=i)
				visited[sg[i-fibonacci[j]]]=true;
			else break;
		for (int j=0;j<=10;j++) //找最小非负整数
			if (!visited[j])
			{
				sg[i]=j;
				break;
			}
	}
}
int main()
{
	first();
	scanf("%d%d%d",&a,&b,&c);
	while (a!=0&&b!=0&&c!=0)
	{
		int k=sg[a]^sg[b];
		int t=k^sg[c];
		if (t==0) printf("Nacci\n"); else printf("Fibo\n");
		scanf("%d%d%d",&a,&b,&c);
	}
}

你可能感兴趣的:(博弈论)