hdu 1848 sg——dfs&&打表双实现

Fibonacci again and again

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6363    Accepted Submission(s): 2646


Problem 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
 

 

Author
lcy
 
由于本题n的范围为1000,所以时间复杂度不是很高
下面两种方法的代码都可以过,,
15086248 2015-10-12 19:11:07 Accepted 1848 0MS 1576K 1320 B G++ 牟柏旭
 
 1   //f[]:可以取走的石子个数
 2     //sg[]:0~n的SG函数值
 3     //Hash[]:mex{}
 4     #include<stdio.h>
 5     #include<string.h>
 6     #include<iostream>
 7     #include<algorithm>
 8     using namespace std;
 9     const int N=1005;
10     const int K=20;
11     int f[K],sg[N],Hash[N];
12     int k;
13     void getSG(int n)
14     {
15             memset(sg,0,sizeof(sg));
16             for(int i=1; i<=n; i++) {
17                     memset(Hash,0,sizeof(Hash));
18                     for(int j=0; f[j]<=i && j < k; j++) //k是f[]的有效长度
19                             Hash[sg[i-f[j]]]=1;
20                     for(int j=0; ; j++) {   //求mes{}中未出现的最小的非负整数
21                             if(Hash[j]==0) {
22                                     sg[i]=j;
23                                     break;
24                             }
25                     }
26             }
27     }
28     int main(){
29        int x1,x2,x3;
30        f[0]=1;
31        f[1]=1;
32        for(int i=2;i<=16;i++)
33         f[i]=f[i-1]+f[i-2];
34         k=17;
35        getSG(1000);
36        while(scanf("%d%d%d",&x1,&x2,&x3)!=EOF){
37           if(x1==0&&x2==0&&x3==0)
38             break;
39           int ans;
40           ans=sg[x1]^sg[x2]^sg[x3];
41           if(ans)
42             printf("Fibo\n");
43           else
44             printf("Nacci\n");
45 
46        }
47        return 0;
48     }

 

 

上面的打表的代码,下面附上dfs代码

15087133 2015-10-12 20:11:06 Accepted 1848 109MS 1880K 1060 B C++ 牟柏旭
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>

using namespace std;
const int k=17;
int s[18],sg[1001];
int getsg(int m)
{
    int hash[21]={0};
    int i;
    for(i=0;i<k;i++){
        if(m-s[i]<0)
            break;
        if(sg[m-s[i]]==-1)
            sg[m-s[i]]=getsg(m-s[i]);
        hash[sg[m-s[i]]]=1;
    }
    for(i=0;;i++)
        if(hash[i]==0)
            return i;


}
int main()
{
    int x[5];
    s[0]=1;
    s[1]=1;
     for(int i=2;i<17;i++)
      s[i]=s[i-1]+s[i-2];
    while(scanf("%d%d%d",&x[1],&x[2],&x[3])!=EOF)
    {
        if(x[1]==0&&x[2]==0&&x[3]==0)
            break;
        int i;

        memset(sg,-1,sizeof(sg));
        sg[0]=0;




            int ans=0;


            for(int i=1;i<=3;i++){
                if(sg[x[i]]==-1)
                    sg[x[i]]=getsg(x[i]);
                ans^=sg[x[i]];
            }
            if(ans)
                cout<<"Fibo"<<endl;
            else cout<<"Nacci"<<endl;


    }
    return 0;
}
15087680 2015-10-12 20:35:01 Accepted 1848 140MS 1772K 1384B C++ 牟柏旭

 

    #include<cstdio>
    #include<string.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int  N=20;
    int knum;
    int si[N],sg[1010];
    int mex(int x)//求x的sg值(可作为模版应用)
    {
        if(sg[x]!=-1)
             return sg[x];
        bool vis[N];
        memset(vis,false,sizeof(vis));
        for(int i=1;i<knum;i++)    {
            int temp=x-si[i];
            if(temp<0)
            break;
            sg[temp]=mex(temp);
            vis[sg[temp]]=true;
        }
        for(int i=0;i<17;i++)    {
            if(!vis[i])    {
                sg[x]=i;
                break;
            }
        }
        return sg[x];
    }
    int main()    {



        int x[5];
       
        while(scanf("%d%d%d",&x[1],&x[2],&x[3])!=EOF)   {
                 if(x[1]==0&&x[2]==0&&x[3]==0)
                break;
                 si[0]=1;
        si[1]=1;
        for(int i=2;i<17;i++)
            si[i]=si[i-1]+si[i-2];
            knum=17;
            memset(sg,-1,sizeof(sg));
            sg[0]=0;

            int ans=0;

                for(int j=1;j<=3;j++) {

                ans^=mex(x[j]);//尼姆博弈
                }
              if(ans==0)
                printf("Nacci\n");
              else
                printf("Fibo\n");

        }
        return 0;
    }

 

 
posted @ 2015-10-12 20:35  柳下_MBX  阅读(345)  评论(0编辑  收藏  举报