zoukankan      html  css  js  c++  java
  • poj 2804 字典 (特里 要么 快排+二分法)

    2804:词典


    总时间限制: 
    3000ms 
    内存限制: 
    65536kB
    描写叙述
    你旅游到了一个国外的城市。那里的人们说的外国语言你不能理解。只是幸运的是,你有一本词典能够帮助你。

    输入
    首先输入一个词典。词典中包含不超过100000个词条。每个词条占领一行。每个词条包含一个英文单词和一个外语单词,两个单词之间用一个空格隔开。并且在词典中不会有某个外语单词出现超过两次。词典之后是一个空行。然后给出一个由外语单词组成的文档,文档不超过100000行。并且每行仅仅包含一个外语单词。输入中出现单词仅仅包含小写字母。并且长度不会超过10。
    输出
    在输出中,你须要把输入文档翻译成英文,每行输出一个英文单词。假设某个外语单词不在词典中。就把这个单词翻译成“eh”。
    例子输入
    dog ogday
    cat atcay
    pig igpay
    froot ootfray
    loops oopslay
    
    atcay
    ittenkay
    oopslay
    
    例子输出
    cat
    eh
    loops
    
    提示
    输入比較大,推荐使用C语言的I / O函数。



    这道题目開始做的时候想到的是字典树;后来由于这道题输入有点特殊。就一直不知道从何下手建树,后来看到别人处理输入的方法;一下子就来了灵感,套用了曾经的模板,把代码敲好提交到百练上就a了,后来在我们学校的oj提交;直接被一个数据难倒了。

    。。(百练的数据有点水啊),后来就一直再想解决的方法。開始的那个程序,假设与给的单词部分匹配直到给的单词结束就输出结果了,可是字典树里面还有,不是全然匹配。当时由于a了就没有考虑到这种情况。一直卡在这里;今天看了别人的ac自己主动机的代码;又给了我一点提示;在

    节点中设置一个单词完结的标记;这种处理,開始我也想了好久,还是有点水啊;一直出现异常的结束。后来最终写好了,感觉还是有点投机取巧的意思,在两个oj上都a了,可是还可以优化;有时候执行还是有问题。我也不知道是什么原因;
    以下是代码;能ac的,还可以优化啊!

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    typedef struct node //节点的结构体
    {
        char eng[12];
        int count; //标记单词是否结束
        struct node * next[26];
    }node;
    int flag;
    void Insert(node *T,char *f,char *e) //插入
    {
        node *p,*q;
        p=T;
        int len,k;
        len=strlen(f);
        if(len==0) return ;
        for(int i=0;i<len;i++)
        {
            k=f[i]-'a';
            if(p->next[k]==NULL)
            {
                q=(node*)malloc(sizeof(node)); //添加新节点
                for(int i=0;i<26;i++)
                {
                    q->count=0;
                    strcpy(q->eng,e);
                    q->next[i]=NULL;
                }
                p->next[k]=q;
                p=q;
            }
            else
                p=p->next[k];
        }
        p->count++;
    }
    void Search(node *T,char *s)//查找
    {
         node *q;
         q=T;
         int k,i=0,len;
         int flag=0;
         for(i=0;i<26;i++)
         {
             k=s[i]-'a';
             q=q->next[k];
             if(q==NULL)
            {
                flag=1;
                printf("eh
    ");
                break;
            }
             if(q->count>0)//单词结束的标记
            {
                 printf("%s
    ",q->eng);
                 flag=1;
                 break;
            }
         }
    }
    void Release(node *T)//销毁
    {
        for(int i=0;i<26;i++)
            if(T->next[i]!=NULL)
                Release(T->next[i]);
            free(T);
    }
    int main()
    {
         //freopen("1.txt","r",stdin);
         char english[20],forigen[20];
         node *T;
         T=(node *)malloc(sizeof(node));
         T->count=0;
         for(int i=0;i<26;i++)
            T->next[i]=NULL;
        while(1)  
        {
            english[0]=getchar();
            if(english[0]=='
    ') break;
            scanf("%s %s",english+1,forigen);
            Insert(T,forigen,english);
            getchar();
        }
        while(scanf("%s",forigen)!=EOF)
        {
            flag=0;
            Search(T,forigen);
        }
        Release(T);
        return 0;
    }
    第一次ac的水代码;
    void Search(char *f)
    {
       node *q;
       int len,k;
       q=T;
       len=strlen(f);
        for(int i=0;i<len;i++)
        {
            k=f[i]-'a';
            q=q->next[k];
            if(q==NULL)
            {
                printf("eh
    ");
                flag=1;
                break;
            }
        }
        if(flag==0) printf("%s
    ",q->eng);//部分匹配就直接输出了
    }
    别人写的字典树代码。好巧妙值得学习;把单词最后一个字符分开处理。做标志,这样就能避免我先前所犯的错误。看了别人的代码,茅塞顿开啊。
    #include "stdio.h"
    #include "string.h"
    #include "math.h"
    #include "algorithm"
    #include "iostream"
    using namespace std;
    
    
    typedef struct  node
    {
          struct node *next[26];
          char   ans[12];
    }node;
    
    
    char arr1[12],arr2[12],str[25];
    node *T;
    
    
    void Diction()
    {
         node *q,*p=T;
         int i,j,k,len;
         len=strlen(arr2);
         for(i=0;i<len-1;i++)
         {
              k=arr2[i]-'a';
              if(p->next[k]==NULL){
                    q=(node*)malloc(sizeof(node));
                    p->next[k]=q;q->ans[0]=0;
                    for(j=0;j<26;j++)
                       q->next[j]=NULL;
                    p=q;
              }else{
                    p=p->next[k];
              }
         }
         k=arr2[i]-'a';//最后一个字符
         if(p->next[k]==NULL){
             q=(node*)malloc(sizeof(node));
             p->next[k]=q;strcpy(q->ans,arr1);//把arr数组复制给最后一个字符的节点;其它节点都是0
               for(j=0;j<26;j++)
                  q->next[j]=NULL;
         }else{
               p=p->next[k];
               strcpy(p->ans,arr1);
         }
    }
    
    
    void search()//查询
    {
           node *p=T;
           int i,len,k;
           len=strlen(str);
           for(i=0;i<len-1;i++)
           {
                  k=str[i]-'a';
                  if(p->next[k]==NULL){
                       printf("eh
    "); 
                       break;
                  }else{
                       p=p->next[k];
                  }
           }
           if(i==len-1)//最后一个字符
           {
                 k=str[i]-'a';
                 if(p->next[k]==NULL){
                       printf("eh
    ");
                 }else{
                       p=p->next[k];
                       if(p->ans[0]!=0)//前面插入那里做的标志
                           puts(p->ans);
                       else
                           printf("eh
    ");
                 }
           }
    }
    int main()
    {
         //freopen("input.txt","r",stdin);
         int i;
         T=(node*)malloc(sizeof(node));
         for(i=0;i<26;i++)
             T->next[i]=NULL;
         while(1)
         {
              gets(str);
              if(strcmp(str,"")==0)
                 break;
              sscanf(str,"%s %s",arr1,arr2);
              Diction();
         }
         while(scanf("%s",str)!=EOF)
                  search();
             return 0;
    }

    另一种思路就是直接用快排+二分的组合,这样的使用方法也非经常见;在这个题目中用到了fgets,sscanf这两个函数。都是第一次用。还用了c语言库里面的qsort和bsearch。然后自己又写了一次二分;比写字典树难度还是小了非常多。非常多细节上还是把握的不好啊;
    以下是ac的代码,直接调用库函数写的。
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    const int maxn=100000+10;
    struct node //节点的结构体
    {
        char eng[12];
        char fore[12];
    };
    node dictionary[maxn];
    int cmp(const void *a,const void *b){ //比較函数
        return strcmp(((node *)a)->fore,((node *)b)->fore);
    }
    int search(const void *a,const void *b){ //二分查找函数
        return strcmp((char *)a,((node *)b)->fore);
    }
    int main()
    {
         //freopen("1.txt","r",stdin);
         char english[30],forigen[20];
         int count=0,flag;
         node *p;
        while(fgets(english,29,stdin)&&english[0]!='
    ')
        {
            sscanf(english,"%s%s",dictionary[count].eng,dictionary[count].fore);
            count++;
        }
        qsort(dictionary,count,sizeof(node),cmp);
       while(scanf("%s",forigen)!=EOF)
        {
            p=NULL;
            p=(node*)bsearch(forigen,dictionary,count,sizeof(node),search);
            if(p)
             printf("%s
    ",p->eng);
            else
                printf("eh
    ");
    }
        return 0;
    }
    自己写得二分查找;
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    const int maxn=100000+10;
    struct node //节点的结构体
    {
        char eng[12];
        char fore[12];
    };
    node dictionary[maxn];
    bool Cmp(node one, node two)
    {
        return strcmp(one.fore, two.fore) < 0;
    }
    int bsearch(char *s,int n) //二分查找
    {
        int mid,start,end;
        start=0;end=n-1;
        int flag=0;
        while(start<=end)
        {
            mid=(start+end)/2;
            flag=strcmp(s,dictionary[mid].fore);
            if(flag==0)
                return mid;
            if(flag<0)
            {
                end=mid-1;
            }
            else
            {
                start=mid+1;
            }
        }
        return -1;
    }
    int main()
    {
         //freopen("1.txt","r",stdin);
         char english[30],forigen[20];
         int count=0,flag;
         node *p;
        while(fgets(english,29,stdin)&&english[0]!='
    ')
        {
            sscanf(english,"%s%s",dictionary[count].eng,dictionary[count].fore);
            count++;
        }
       sort(dictionary,dictionary+count,Cmp);
        while(scanf("%s",forigen)!=EOF)
        {
          flag=bsearch(forigen,count);
            if(flag!=-1)
            {
                printf("%s
    ",dictionary[flag].eng);
            }
            else
                printf("eh
    ");
        }
        return 0;
    }
    
    在平时做题中还是要多积累。
    总结:这个题目能够用多种思路去做,平时练习能够多去尝试一下,熟悉一下库函数。fgets,sscanf对输入格式的控制;qsort中cmp函数的格式。还用bsearch里面search函数的写法和格式,传递的參数。对于字典树在模板的基础上还要依据题意灵活处理,像这道题的话,设置一个參数表示结束就会非常方便;
    标题不,在晴朗。。


     
  • 相关阅读:
    Keepalived详解(一):Keepalived介绍【转】
    Python运维开发基础06-语法基础【转】
    Python运维开发基础05-语法基础【转】
    Python运维开发基础04-语法基础【转】
    Python运维开发基础03-语法基础 【转】
    Python运维开发基础02-语法基础【转】
    Python运维开发基础01-语法基础【转】
    Shell编程中while与for的区别及用法详解【转】
    rsync+inotify实现实时同步案例【转】
    Linux查看压缩文件内容【转】
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5032892.html
Copyright © 2011-2022 走看看