题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1848
学完三个基本的博弈论后,只能解决有限的博弈问题,因此我又开始看sg函数,然而看的并不很理解,看了许多博客后,发现
sg函数是一个根据可选步数来打一个表,这个表是从1到堆中最大可放的石子的数量n中每个数对应的状态,可以根据这个表中
的书来异或求知否为奇异状态,因此暂时可以根据模板来做题,至于理解证明过程,可以慢慢来嘛,,以后回过头看会有不一
样的收获。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define N 1001using namespace std;/*
a[](存储可以走的步数, 需要从小到大排序);
1.可选步数为1-m的连续整数,直接取模即可,Sg(x)=x%(m+1);
2.可选步数为任意步,Sg(x) = x;
3.可选步数为一系列不连续的数,用getSg(计算) ;
本题选用第三种方法,因为菲波那契数列为不连续数列;
*/int a[21];
int sg[N];
bool vis[N];//获取sg的模板
void getSg(int n) //n为堆中可放入的最大石子数
{int i, j;memset(sg, 0, sizeof(sg));for(i=1; i<=n; i++){memset(vis, 0, sizeof(vis));for(j=1; a[j]<=i; j++ )vis[sg[i-a[j]]]=1;for(j=0; j<=n; j++ ){if(!vis[j]){sg[i] = j;break;}}}
}
int main()
{int i, m, n, p;a[0]=1, a[1]=1;for(i=2; i<21; ++i)a[i] = a[i-1] + a[i-2];getSg(1000);while(scanf("%d%d%d", &m, &n, &p)){if(m==0 && n==0 && p==0)break;if((sg[m] ^ sg[n] ^ sg[p]) == 0) //奇异状态先手必输printf("Nacci\n");elseprintf("Fibo\n");}return 0;
}