POJ2001Shortest Prefixes(字典树)
题目大意就是帮你给N条字符串,每条长度不超过20。问要将他们单一识别出来,每个字符串最短可以缩为多短。
如:
abc
abcdefg
bc
adef
这四个字符串就可分别缩写为
abc
abcd
b
ad
方法: 字典树(可以参阅http://s.acmore.net/show_article/show/58)。
另外我还用了一个bool数组last用来记录每个单一识别的字符串最短可以到哪个位置,他的下标就是字典树中每个字母对应的序号
方法如下:(以上面的为例)
当输入的字符串在某一个位置开始与之前的不同,就记录这个不同的字母(设置为true),之后的不再改变
当输入字符串的某位置在建好的树中时,把last加长(设置为true)
第一次输入:abc last[0]=true;
第二次输入:abcdefg last[0]=last[1]=last[2]=last[3]=true;
第三次输入:bc last[0]=true;
第四次输入:adef last[0]=last[1]=true;
这样一来输出端长度就分别为1、4、1、2
代码实现如下:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <stack> 6 #include <set> 7 #include <queue> 8 #define MAX(a,b) (a) > (b)? (a):(b) 9 #define MIN(a,b) (a) < (b)? (a):(b) 10 #define mem(a) memset(a,0,sizeof(a)) 11 #define INF 1000000007 12 #define MAXN 20005 13 using namespace std; 14 15 int trie[MAXN][26],val[MAXN],S; 16 bool last[MAXN]; 17 char ma[1005][30]; 18 19 int get_num(char ch){return ch-'a';} 20 21 void init() 22 { 23 mem(trie);mem(val); 24 mem(last);mem(ma); 25 S = 1; 26 } 27 28 void insert(char *s) 29 { 30 int u=0,len = strlen(s); 31 int flag = 1; 32 for(int i=0;i<len;i++) 33 { 34 int c = get_num(s[i]); 35 if(!trie[u][c]) 36 { 37 trie[u][c] = S; 38 val[u] = 1; 39 if(flag)//如果与上面的字符串开始不一样,酒吧第一个开始不一样的位置设置为true 40 { 41 last[u]=true; 42 flag = 0;//之后的依然是false 43 } 44 u = S; 45 S++; 46 } 47 else if(val[u] == 1) 48 { 49 u = trie[u][c]; 50 last[u] = true;//在查找中发现与已建好的树里面相同的数,那么需要识别的字符串就要相应的加长 51 } 52 } 53 if(val[u]==1 || val[u] == 2)return; 54 else val[u] = 2; 55 } 56 57 int main() 58 { 59 init(); 60 int T =0; 61 while(scanf("%s",ma[T])!=EOF) 62 { 63 insert(ma[T++]); 64 } 65 for(int i=0;i<T;i++) 66 { 67 printf("%s ",ma[i]); 68 int u=0,j=0; 69 while(last[u] && ma[i][j]) 70 { 71 printf("%c",ma[i][j]); 72 u = trie[u][get_num(ma[i][j++])]; 73 } 74 printf("\n"); 75 } 76 return 0; 77 }