传送门
https://vjudge.net/problem/POJ-2001
题目大意就是求每一个字符串的最短前缀,并且这个前缀其他字符串都没有。
一道trie树板子题。建树的时候,每一个结点维护的是经过这个状态的字符串有多少个。然后查询的时候,对于每一个字符串,从头开始跑trie树,找到第一个数是1的结点。那么从头到这个节点经过的边就是所求前缀。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 using namespace std; 7 typedef long long ll; 8 #define enter printf("\n") 9 const int maxn_num = 2e4 +5; 10 const int maxn_size = 30; 11 const int INF = 0x3f3f3f3f; 12 13 struct Trie 14 { 15 int ch[maxn_num][maxn_size], val[maxn_num]; 16 /*ch[i][j]代表第i个结点,经过边权为j的边所到达的结点 17 所以ch的第一维应该开字符串数目*字符种类数*/ 18 int tot; //结点个数 19 Trie() 20 { 21 tot = 1; memset(val, 0, sizeof(val)); 22 memset(ch, 0, sizeof(ch)); 23 } 24 int change(char c) {return c - 'a';} 25 void Insert(char *s) 26 { 27 int now = 0; 28 for(int i = 0; i < strlen(s); ++i) 29 { 30 int c = change(s[i]); 31 if(!ch[now][c]) ch[now][c] = tot++; //新开结点 32 now = ch[now][c]; val[now]++; 33 } 34 } 35 void query(char *s) 36 { 37 int now = 0; 38 for(int i = 0; i < strlen(s); ++i) 39 { 40 printf("%c", s[i]); 41 int c = change(s[i]); 42 if(val[ch[now][c]] == 1) break; 43 now = ch[now][c]; 44 } 45 enter; 46 } 47 }trie; 48 49 char s[1005][50]; 50 51 int main() 52 { 53 int x = 0; 54 while(scanf("%s", s[++x]) != EOF) 55 trie.Insert(s[x]); 56 for(int i = 1; i <= x; ++i) 57 { 58 printf("%s ", s[i]); 59 trie.query(s[i]); 60 } 61 return 0; 62 }