CSU 1115: 最短的名字(字典树)
1115: 最短的名字
题目链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1115
Description
在一个奇怪的村子中,很多人的名字都很长,比如aaaaa, bbb and abababab。
名字这么长,叫全名显然起来很不方便。所以村民之间一般只叫名字的前缀。比如叫'aaaaa'的时候可以只叫'aaa',因为没有第二个人名字的前三个字母是'aaa'。不过你不能叫'a',因为有两个人的名字都以'a'开头。村里的人都很聪明,他们总是用最短的称呼叫人。输入保证村里不会有一个人的名字是另外一个人名字的前缀(作为推论,任意两个人的名字都不会相同)。
如果村里的某个人要叫所有人的名字(包括他自己),他一共会说多少个字母?
Input
输入第一行为数据组数T (T<=10)。每组数据第一行为一个整数n(1<=n<=1000),即村里的人数。以下n行每行为一个人的名字(仅有小写字母组成)。输入保证一个村里所有人名字的长度之和不超过1,000,000。
Output
对于每组数据,输出所有人名字的字母总数。
Sample Input
1
3
aaaaa
bbb
abababab
Sample Output
5
HINT
Source
字典树查找,只要找到前面重叠层某个字符的个数为1或找到啦此字符串的最后一个字符,就返回当前的字符的长度(即树的层数)。。。。。。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 using namespace std; 6 7 struct node 8 { 9 node *a[27]; //存放当前字符后面那一个字符的存放的地址 10 int p; //记录此字符在这一层的个数 11 }*t,*h; 12 13 char s[1005][1005]; 14 int i,j,t0,n,l; 15 16 void make(int k,node* h) //建树 17 { 18 h->p++; 计算s[k][j]字符的个数; 19 if(k>l) return ; 20 if(h->a[s[i][k]-'a']!=NULL) make(k+1,h->a[s[i][k]-'a']); 21 else 22 { 23 int x,j; 24 for(x=k;x<=l;x++) 25 { 26 t=new node; //创建新结点 27 t->p=1; 28 for(j=0;j<26;j++) t->a[j]=NULL; 29 h->a[s[i][x]-'a']=t; //保存s[i][x]字符后面那一个字符的存放的地址 30 h=t; 31 } 32 } 33 return; 34 } 35 36 void find(int k,int m,node* h) //查找 37 { 38 t0++; 39 if(k==strlen(s[m])-1||h->p==1) return ; 40 find(k+1,m,h->a[s[m][k+1]-'a']); 41 } 42 43 void release(struct node* now) //释放内存 44 { 45 if(now==NULL) return ; 46 for(int i=0;i<26;i++) 47 { 48 if(now->a[i]) 49 { 50 release(now->a[i]); 51 now->a[i]=NULL; 52 } 53 } 54 free(now); 55 } 56 int main() 57 { 58 int T; 59 scanf("%d",&T); 60 while(T--) 61 { 62 scanf("%d",&n); 63 h=new node; //先创建一个结点 64 h->p=0; 65 for(i=0;i<26;i++) h->a[i]=NULL; 66 for(i=1;i<=n;i++) 67 { 68 scanf("%s",s[i]); 69 l=strlen(s[i])-1; 70 make(0,h); 71 } 72 int sum=0; 73 for(i=1;i<=n;i++) 74 { 75 t0=0; 76 find(0,i,h->a[s[i][0]-'a']); 77 sum+=t0; 78 } 79 release(h); 80 printf("%d\n",sum); 81 } 82 return 0; 83 }