Fibonacci again and again
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 6854 Accepted Submission(s): 2848
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、 最先取光所有石子的人为胜者;
假设双方都使用最优策略,请判断先手的人会赢还是后手的人会赢。
m=n=p=0则表示输入结束。
1 1 1 1 4 1 0 0 0
Fibo Nacci
SG函数的基本应用,什么是SG函数??这个我不能多说,资料很多,何况我也是刚刚接触,万一误导大家。
这样来看,如果对于单一堆的话。他的取法会怎么样?对于总数为 fibonacci 数列中的数,先手肯定必胜,例如总数为 1 2 3 5 8,那么对于其他情况那?这里我们首先来考虑一个 4 。对于 4
无论先手怎样取,都会失败,也就是说4是一个必败点!假定此处的 SG 为 0 。然后再来考虑一个特殊点 0 ,此时无数可取,当然也是必败。次数 SG 也设为 0 。
那么 对于必胜点来说 SG != 0 ,必败点 SG=0 ,相信这个为什么不用我多说吧,如果不知道,还是去看一下有关SG函数的知识。
贴出传送门: 传送门已就绪~~
对于 1 来说,他的取法只有 1
也就是说 1 - 1 = 0 , 和 0 等价的只有 0
1 的全部后继节点 构成一个集合 { 0 }
对这个集合进行运算 mex { 0 } = 1 。也就是说 SG (1)= 1.
对于 2 来说,他的取法有 1 和 2
可以得到的剩余个数 1 0 , 1 和 1 等价,0 和 0 等价 ,
mex{ 0 , 1 } =2 ; SG(2)=2;
3 也是同样,我们来看 4几个特殊的。
对于 4 来说 取法有 1 , 2 , 3
可以得到的剩余个数有 3,2,1. 分别和 3, 2 , 1 等价
mes(1,2,3)=0; SG(4)=0 ,我们上面已经知道4 是必败点。
对于 5 取法有 1 2 3 5
可以得到剩余的个数 4,3,2,0. 通过上面我们知道 SG(4)=0,也就是说 剩余 4个 和剩余0个没有区别,都是必败点。所以 他们分别等价于 0 3 2 0
mex{0,2,3}=1; SG(5)=1; 也就是说 5 和 1 是等价的,这个可以理解吗?不理解的话,就请思考几遍。
再来看一个
剩余个数 6 7 8
可取个数 1 2 3 5 1 2 3 5 1 2 3 5 8
剩余个数 5 4 3 1 6 5 4 2 7 6 5 3 0
等价于 1 0 3 1 2 1 0 2 3 2 1 3 0
mex运算 2 3 4
等价于可以看做 其 SG 值。
那么SG值代表什么呢?
假设 x 出 SG 值为 k,
那么 意义就是:x 的后继节点 出 sg 值可以为 0,1,2,......,k-1,甚至是 k+1,但是不可以保持k不变。因为每次操作都是要改变状态的!
而另外定义的运算mex是用来干什么的那??
我的理解是这样的!!咳咳~~
在nimu博弈里面, p 和 n 的转化关系还记得吗?
p 的后继节点至少有一个 n n 的所有后继节点都是 p
也就是说,SG = 0 时,下一个 总是 SG != 0
SG != 0 时,后继节点至少有一个 SG = 0;
而mex运算就是用来实现这个的功能的,求出最小的SG可能。那么他可以达到的后继都比他小,对吗?
我不知道我是否说的清楚。
然后SG不是还有一个性质吗?
SG _total = SG (1) ^ SG (2) ^ ......SG (n).
具体为什么?
还有为什么 SG = 0 为必败,SG != 0 为必胜?
结合着拓扑图,我试着来证明一下。(证明不出来的话大家就别看了。)
先来看一下 对于一堆小石块的游戏。
对于 1 2 显然是 必胜点,对于 3 他只能通向必胜点,也就是说他的下一步操作会将必胜点送给对手。
对于 4 呢?可以选择把必胜给对方,也可以选择把必败给对方。当然最优抉择是把必败给对方。
我们完全可以用 p n 来表示整个图。SG != 0 为 p 否则 为 n 。
这样的话。因为 p n 的转化关系。(尼姆博弈里面说的很详细了,包括证明都很厉害)
再来看下一个问题:
为什么对于多组博弈
SG _total = SG (1) ^ SG (2) ^ ......SG (n).
再回到尼姆博弈中来......
还记得当时证明为什么在尼姆博弈中 sum ^ 后为0 就输,不为 0 就胜吗?
其实这个证明和那个完全相同
贴出传送门:不会的同学去看一下:
感觉写的很乱的。希望对看到的同学有帮助。
感想:
这个东西想了一天了,累死,今天终于有点懂了。博弈就先搞到这里吧,先去学点别的压压惊。。
AC代码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <queue>
#include <stack>
#include <iostream>
#include <algorithm>
using namespace std;
int sg[1005];
int fibo[1005];
int mex[1005];
int main()
{
int a,b,c,pp,i,j;
fibo[0]=fibo[1]=1;
fibo[2]=2;
for(i=3;i<1004;i++)
{
fibo[i]=fibo[i-1]+fibo[i-2];
}
memset(sg,0,sizeof(sg));
sg[1]=1;//这里是必胜点设为 p
sg[2]=2;
sg[3]=3;
for(i=4;i<1002;i++)
{
memset(mex,0,sizeof(mex));
for(j=0;fibo[j]<=i;j++)
mex[sg[i-fibo[j]]]=1;
for(j=0;;j++)
{
if(mex[j]==0)
{
sg[i]=j;
break;
}
}
}
while(cin>>a>>b>>c)
{
pp=0;
int num=0;
int sum=0;
if(a+b+c==0) break;
sum=sg[a]^sg[b]^sg[c];
//cout<<sum<<endl;
if(!sum)
{
cout<<"Nacci"<<endl;
}
else
cout<<"Fibo"<<endl;
}
return 0;
}