poj 2804 詞典 (字典樹 或者 快排+二分),poj2804

來源:互聯網
上載者:User

poj 2804 詞典 (字典樹 或者 快排+二分),poj2804
2804:詞典


總時間限制: 
3000ms 
記憶體限制: 
65536kB
描述
你旅遊到了一個國外的城市。那裡的人們說的外國語言你不能理解。不過幸運的是,你有一本詞典可以協助你。
輸入
首先輸入一個詞典,詞典中包含不超過100000個詞條,每個詞條佔據一行。每一個詞條包括一個英文單詞和一個外語單詞,兩個單詞之間用一個空格隔開。而且在詞典中不會有某個外語單詞出現超過兩次。詞典之後是一個空行,然後給出一個由外語單片語成的文檔,文檔不超過100000行,而且每行只包括一個外語單詞。輸入中出現單詞只包括小寫字母,而且長度不會超過10。
輸出
在輸出中,你需要把輸入文檔翻譯成英文,每行輸出一個英文單詞。如果某個外語單詞不在詞典中,就把這個單詞翻譯成“eh”。
範例輸入
dog ogdaycat atcaypig igpayfroot ootfrayloops oopslayatcayittenkayoopslay
範例輸出
catehloops
提示
輸入比較大,推薦使用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\n");            break;        }         if(q->count>0)//單詞結束的標記        {             printf("%s\n",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]=='\n') 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\n");            flag=1;            break;        }    }    if(flag==0) printf("%s\n",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\n");                    break;              }else{                   p=p->next[k];              }       }       if(i==len-1)//最後一個字元       {             k=str[i]-'a';             if(p->next[k]==NULL){                   printf("eh\n");             }else{                   p=p->next[k];                   if(p->ans[0]!=0)//前面插入那裡做的標誌                       puts(p->ans);                   else                       printf("eh\n");             }       }}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]!='\n')    {        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\n",p->eng);        else            printf("eh\n");}    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]!='\n')    {        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\n",dictionary[flag].eng);        }        else            printf("eh\n");    }    return 0;}
在平時做題中還是要多積累;
總結:這個題目可以用多種思路去做,平時練習可以多去嘗試一下,熟悉一下庫函數;fgets,sscanf對輸入格式的控制;qsort中cmp函數的格式,還用bsearch裡面search函數的寫法和格式,傳遞的參數;對於字典樹在模板的基礎上還要根據題意靈活處理,像這道題的話,設定一個參數表示結束就會很方便;
題不在多,在精!!


 

poj 詞典 2804 答案

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100001
struct node
{
char s[12];
char t[12];
}str[MAX];
char a[12];
int cmp(const void *a,const void *b) //快排
{
return strcmp(((struct node *)a)->t, ((struct node *)b)->t);
};
void bsearch1(char key[],int n) //二分的方法
{
int low=0,high=n-1,mid,f=0;
while(low<=high)
{
mid=(low+high)/2;
if(!strcmp(str[mid].t,key))
{
f=1;
printf("%s\n",str[mid].s);
}
if(strcmp(str[0].t,str[n-1].t)<0)
{
if(strcmp(str[mid].t,key)>0)
high = mid-1;
else
low = mid+1;
}
else
{
if(strcmp(key,str[mid].t)<0)
low=mid+1;
else
high=mid-1;
}
}
if(!f)
printf("eh\n");
}
main()
{
int i=0,j=0,k=0;
while(scanf("%s",&str[i].s)!=EOF) //讀入字串也得注意;
{
if(getchar()=='\n')
break;
else
{
scanf("%s",&str[i].t);
++i;
}
}
qsort(str,i,sizeof(node),cmp);
strcpy(a,str[i].s); bsearch1(a,i);//單獨考慮這次情況,因為s最後將它也讀入了。
while(scanf("%s",a)!=EOF)
{
int f=0;
bsearch1(a,i);
}
}...餘下全文>>
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.