斐波那契博弈?!

Description

有一堆石子有n颗,双方轮流取石子。
先手第一次可以拿至少一个但是不能拿完
接下来每次取的石子至少为1个,至多为上一次拿的两倍
问先手是否有必胜策略

Solution

观(da)察(biao)发现先手必败当且仅当n为斐波那契数?!!!
考虑归纳证明:
设n是斐波那契数,n=a+b,a和b为n的前两个斐波那契数
设先手拿的石子数量为x,显然x<a,因为b<2*a
那么根据归纳,后手肯定可以取到第a颗石子(a为先手必败)
剩下的就是一个状态为b的子游戏,也是先手必败
但是唯一的问题就是后手取完a之后,先手是否能够一步将b取完
考虑后手要取到a一次最多取多少个,设为y
那么也就是x>=a/3,y<=2a/3
那么下一步先手最多能取4a/3颗石子,和b做比较显然后者大
也就是说先手一定不能一次取完b,所以先手必败

如果n不是斐波那契数,根据齐肯多夫定理n可以被分解成若干个不相邻的斐波那契数之和,设为Fib[a[1]]…Fib[a[k]],且Fib[a[i]]>2*Fib[a[i+1]]
那么先手只需要取完Fib[a[k]],后手一次取不完Fib[a[k-1]],所以变成了一个子游戏,根据上面的分析先手一定能够取到最后一颗
所以先手必胜

HDU2516取石子游戏

#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

int n,f[46];
map<int,int> fib;

int main() {
	f[0]=f[1]=1;fib[1]=1;
	fo(i,2,45) {
		f[i]=f[i-1]+f[i-2];
		fib[f[i]]=1;
	}
	while(scanf("%d",&n)) {
		if (!n) break;
		if (fib[n]) puts("Second win");
		else puts("First win");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值