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);
}
}...餘下全文>>