题目链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1115
解题报告:输入n个字符串,让你求出可以用来区别这些字符串的最少的前缀总共有多少个字母。可以区别是指每个字符串都取一个自己的前缀,同时保证所有取的这些前缀没有完全相同。
这题用字典树可以做,就是输入的时候把所有的字符串都插入到字典树中,最后把所有被走过不止一次的节点的值都加起来,每个节点的值表示这个节点被走过多少次,然后如果碰到这个节点的值是1的时候总和加1,同时要退出,后面的就不用统计了,因为这个节点只被走过一次,所以经过这个节点的那个字符串到这里已经是唯一的了。
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cmath> #include<deque> #include<map> #include<queue> #include<cstdlib> using namespace std; const int maxn = 1005; char temp[1000005]; int ans; typedef struct node { node* ch[26]; int tot; }*Linklist; void Init(Linklist& p) { p->tot = 0; for(int i = 0;i < 26;++i) p->ch[i] = NULL; } void push(Linklist p,char* str,int f,int len) { if(f >= len) return ; if(p->ch[str[f]-'a'] == NULL) { p->ch[str[f]-'a'] = new node; Init(p->ch[str[f]-'a']); p->ch[str[f]-'a']->tot++; p = p->ch[str[f]-'a']; } else { p->ch[str[f]-'a']->tot++; p = p->ch[str[f]-'a']; } push(p,str,f+1,len); } void get_tot(Linklist p) { if(p == NULL || p->tot == 1) { if(p != NULL && p->tot == 1) ans++; return ; } else ans += p->tot; for(int i = 0;i < 26;++i) get_tot(p->ch[i]); } void clean(Linklist p) { if(p == NULL) return ; for(int i = 0;i < 26;++i) if(p->ch[i] != NULL) clean(p->ch[i]); delete p; } int main() { int T,n; scanf("%d",&T); while(T--) { scanf("%d",&n); Linklist head = new node; Init(head); for(int i = 0;i < n;++i) { scanf("%s",temp); push(head,temp,0,strlen(temp)); } // printf("%d %d %d %d ",head->ch[0]->tot,head->ch[0]->ch[0]->tot,head->ch[0]->ch[1]->tot,head->ch[1]->tot); ans = 0; for(int i = 0;i < 26;++i) get_tot(head->ch[i]); printf("%d ",ans); clean(head); } return 0; }