这道题也是卡了挺久的。
给出一个字符串比较的算法,有n个字符串两两比较一次,问一共会有多少次比较。
因为节点会很多,所以Tire树采用了左儿子右兄弟的表示法来节省空间。
假设两个不相等的字符串的最长公共前缀的长度为i,那么比较次数应该是2i+1。
如果两个字符串相等,比较次数则是2i+2.
可以像大白书上一样先构建好Tire树,然后DFS统计答案。
1 #include <cstdio> 2 #include <cstring> 3 4 const int maxnode = 4000 * 1000 + 10; 5 6 struct Tire 7 { 8 int sz; 9 int son[maxnode], bro[maxnode], tot[maxnode]; 10 char ch[maxnode]; 11 long long ans; 12 void clear() { sz = 1; son[0] = bro[0] = tot[0] = 0; } 13 14 void insert(char* s) 15 { 16 int u = 0, v, n = strlen(s); 17 tot[0]++; 18 for(int i = 0; i <= n; i++) 19 { 20 bool found = false; 21 for(v = son[u]; v; v = bro[v]) 22 if(ch[v] == s[i]) { found = true; break; } 23 if(!found) 24 { 25 v = sz++; 26 son[v] = 0; 27 bro[v] = son[u]; 28 son[u] = v; 29 tot[v] = 0; 30 ch[v] = s[i]; 31 } 32 u = v; 33 tot[u]++; 34 } 35 } 36 37 void dfs(int d, int u) 38 { 39 if(son[u] == 0) { ans += tot[u] * (tot[u]-1) * d; return; }//叶节点 40 long long sum = 0; 41 for(int v = son[u]; v; v = bro[v]) 42 sum += tot[v] * (tot[u] - tot[v]); 43 ans += sum / 2 * (d * 2 + 1); 44 for(int v = son[u]; v; v = bro[v]) dfs(d+1, v); 45 } 46 47 long long count() 48 { 49 ans = 0; 50 dfs(0, 0); 51 return ans; 52 } 53 }tire; 54 55 const int maxl = 1000 + 10; 56 char s[maxl]; 57 58 int main() 59 { 60 //freopen("in.txt", "r", stdin); 61 62 int n, kase = 0; 63 while(scanf("%d", &n) == 1 && n) 64 { 65 tire.clear(); 66 for(int i = 0; i < n; i++) { scanf("%s", s); tire.insert(s); } 67 printf("Case %d: %lld\n", ++kase, tire.count()); 68 } 69 70 return 0; 71 }
代码君
也可以边插入字符串边统计,代码更短,而且速度也更快。这种做法是从某位菊苣的博客中看到的。
1 #include <cstdio> 2 #include <cstring> 3 4 const int maxnode = 1000 * 4000 + 10; 5 6 long long ans; 7 8 struct Tire 9 { 10 int son[maxnode], bro[maxnode], tot[maxnode]; 11 char ch[maxnode]; 12 int sz; 13 void clear() { sz = 1; son[0] = bro[0] = tot[0] = 0; } 14 15 void insert(char* s) 16 { 17 int u = 0, v, n = strlen(s); 18 tot[0]++; 19 for(int i = 0; i <= n; i++) 20 { 21 bool found = false; 22 for(v = son[u]; v; v = bro[v]) 23 if(ch[v] == s[i]) { found = true; break; } 24 if(!found) 25 { 26 v = sz++; 27 son[v] = 0; 28 bro[v] = son[u]; 29 son[u] = v; 30 tot[v] = 0; 31 ch[v] = s[i]; 32 } 33 ans += (tot[u] - 1 - tot[v]) * (2 * i + 1); 34 if(i == n) ans += tot[v] * (2 * i + 2); 35 u = v; 36 tot[u]++; 37 } 38 } 39 }tire; 40 41 const int maxl = 1000 + 10; 42 char s[maxl]; 43 44 int main() 45 { 46 //freopen("in.txt", "r", stdin); 47 48 int n, kase = 0; 49 while(scanf("%d", &n) == 1 && n) 50 { 51 tire.clear(); 52 ans = 0; 53 for(int i = 0; i < n; i++) { scanf("%s", s); tire.insert(s); } 54 printf("Case %d: %lld\n", ++kase, ans); 55 } 56 57 return 0; 58 }
代码君
时间: 2024-10-09 00:11:51