Trie 字典樹
阿新 • • 發佈:2017-09-11
src spa main ets strcmp() ems next arc ear
1、UVa 1401 Remember the Word
題意:給出n個字符串集合,問其有多少種組合方式形成目標字符串。
思路:對n個字符串集合建立Trie樹,保存每個結點的字符串的順序編號。然後對這棵樹查找目標字符串每一個後綴的前綴字符串,累加。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<vector> 6 using namespace std;View Code7 const int MOD = 20071027; 8 struct Trie 9 { 10 int word[4001 * 100][26]; 11 int ex[4001 * 100]; 12 int size; 13 14 void clear() 15 { 16 memset(word[0], 0, sizeof(word[0])); 17 size = 1; 18 ex[0] = 0; 19 } 20 21 void insert(char *s, int v) 22 {23 int Now = 0, curchr; 24 for (int i = 0; s[i] != ‘\0‘; i++) 25 { 26 int c = s[i] - ‘a‘; 27 if (!word[Now][c]) 28 { 29 memset(word[size], 0, sizeof(word[size])); 30 ex[size] = 0; 31 word[Now][c] = size++;32 } 33 Now = word[Now][c]; 34 } 35 ex[Now] = v; 36 } 37 38 int search(char *s, int len, vector<int>& ans) 39 { 40 int u = 0, c; 41 for (int i = 0; s[i] != ‘\0‘&&i<len; i++) 42 { 43 c = s[i] - ‘a‘; 44 if (!word[u][c])return 0; 45 u = word[u][c]; 46 if (ex[u]) 47 ans.push_back(ex[u]); 48 } 49 } 50 } tree; 51 52 char s[300001]; 53 char tmp[101]; 54 int dp[300001]; 55 int n; 56 int ll[4001];//記錄每個字符串的長度 57 int main() 58 { 59 int Case = 1; 60 while (~scanf("%s",s)) 61 { 62 scanf("%d", &n); 63 tree.clear(); 64 memset(dp, 0, sizeof(dp)); 65 int len = strlen(s); 66 67 for (int i = 0; i<n; i++) 68 { 69 scanf("%s", tmp); 70 ll[i + 1] = strlen(tmp); 71 tree.insert(tmp, i + 1); 72 } 73 dp[len] = 1; 74 for (int i = len - 1; i >= 0; i--) 75 {//找下標為i~len-1的子字符串的前綴字符串 76 vector<int>ans; 77 tree.search(s + i, len - i, ans); 78 for (int j = 0; j<ans.size(); j++) 79 dp[i] = (dp[i] + dp[i + ll[ans[j]]]) % MOD; 80 } 81 printf("Case %d: %d\n", Case++, dp[0]); 82 } 83 return 0; 84 }
2、UVA 11732 strcmp() Anyone?
題意:給n個長度不超過1000的字符串,兩兩字符串比較,某一位相同比較2次,不相同比較1次,問需要比較多少次。
思路:左兒子右兄弟法表示Trie樹。向右找相同字符,向左添加新字符,同一兄弟層表示在同一位的字符。
參考:http://www.cnblogs.com/sineatos/p/3888815.html
1 #include <cstdio> 2 #include <cstring> 3 #define MAXN 4001010 4 #define ll long long 5 using namespace std; 6 //左兒子右兄弟表示字典樹 7 int head[MAXN];// head[i]為第i個結點的左兒子編號 8 int next[MAXN];// next[i]為第i個結點的右兄弟編號 9 int tot[MAXN];// tot[i]為第i個結點為根的子樹包含的葉結點(即以包含其的前綴的字符串個數)總數 10 int ed[MAXN];// ed[i]為第i個結點結束的字符串的個數 11 char ch[MAXN];// ch[i]為第i個結點上的字符 12 int sz; 13 ll sum; 14 void init() 15 {// 初始時只有一個根結點 16 sz = 1; head[0] = next[0] = tot[0] = 0; sum = 0; 17 } 18 19 void insert(char *s) 20 { 21 int u, v, n = strlen(s); 22 u = 0; 23 for (int i = 0; i<n; i++) 24 { 25 bool f = 0; 26 for (v = head[u]; v != 0; v = next[v]) 27 {//找字符s[i] 28 if (ch[v] == s[i]) 29 { 30 f = 1; break; 31 } 32 } 33 if (!f) 34 {//如果沒找到,新建結點 35 v = sz++; 36 tot[v] = 0; 37 ed[v] = 0; 38 ch[v] = s[i]; 39 next[v] = head[u];//插入首部 40 head[u] = v; 41 head[v] = 0; 42 } 43 u = v; 44 sum += tot[v] * 2; 45 tot[v]++; 46 } 47 sum += ed[u]; 48 ed[u]++; 49 } 50 int main() 51 { 52 int n; 53 char s[1002]; 54 int Case = 1; 55 while(~scanf("%d", &n)&&n) 56 { 57 init(); 58 for (int i = 0; i<n; i++) 59 { 60 scanf("%s", s); 61 insert(s); 62 } 63 printf("Case %d: %lld\n", Case++, sum + n*(n - 1) / 2); 64 } 65 return 0; 66 }View Code
3、uva 11488 Hyper Prefix Sets
題意:求n個給出的01串的最長公共前綴的長度*n的值。
思路:字典樹,每次插入一個新的01串,累計每個結點的前綴的長度。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 6 const int maxn = 10000010; 7 const int Char_size = 2; 8 struct Trie 9 { 10 int word[maxn][Char_size];//結點 11 int val[maxn];//附加信息 12 int size;//總結點數 13 int ans; 14 15 void Init() 16 { 17 memset(word[0], 0, sizeof(word[0])); 18 size = 1; 19 val[0] = 0; 20 ans = 0; 21 } 22 int getID(char c) 23 { 24 return c - ‘0‘; 25 } 26 void Insert(char *s) 27 { 28 int now = 0, curchr; 29 for (int i = 0; s[i] != ‘\0‘; i++) 30 { 31 int pos =getID(s[i]); 32 if (!word[now][pos]) 33 { 34 memset(word[size], 0, sizeof(word[size])); 35 val[size] = 0; 36 word[now][pos] = size++; 37 } 38 now = word[now][pos]; 39 val[now] += i + 1;//累加到該結點的前綴的長度 40 ans = max(ans, val[now]); 41 } 42 } 43 }tree; 44 45 char str[maxn]; 46 int main() 47 { 48 int t; 49 scanf("%d", &t); 50 while (t--) 51 { 52 tree.Init(); 53 int n; 54 scanf("%d", &n); 55 while (n--) 56 { 57 scanf("%s", str); 58 tree.Insert(str); 59 } 60 printf("%d\n", tree.ans); 61 } 62 return 0; 63 }View Code
Trie 字典樹