UVa 11732 (Tire树) "strcmp()" Anyone?

这道题也是卡了挺久的。

给出一个字符串比较的算法,有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

UVa 11732 (Tire树) "strcmp()" Anyone?的相关文章

UVa 1401 (Tire树) Remember the Word

d(i)表示从i开始的后缀即S[i, L-1]的分解方法数,字符串为S[0, L-1] 则有d(i) = sum{ d(i+len(x)) | 单词x是S[i, L-1]的前缀 } 递推边界为d(L) = 1,代表空串. 将前n个单词构造一颗Tire树,在树中查找后缀的过程中遇到一个单词节点就代表找到一个状态转移中的x 1 #include <cstdio> 2 #include <cstring> 3 4 const int maxnode = 400000 + 10; 5 co

uva 11732 - strcmp() Anyone?(字典树)

题目链接:uva 11732 - strcmp() Anyone? 题目大意:给定n个串,然后两两之间比较,问说总共要比较多少次. 解题思路:字典树,建立出字典树,然后根据字典树的性质在节点记录有多少个字符串包含该节点.因为节点的个数比较多,所以用左孩子右兄弟的方法建立字典树. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long

UVa - 11732 - strcmp() Anyone?

先上题目: strcmp() Anyone? Time Limit:2000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Description J ?strcmp()? Anyone? Input: Standard Input Output: Standard Output strcmp() is a library function in C/C++ which compares two stri

UVA 11732 - strcmp() Anyone?(Trie)

UVA 11732 - strcmp() Anyone? 题目链接 题意:给定一些字符串,要求两两比较,需要比较的总次数(注意,如果一个字符相同,实际上要还要和'\0'比一次,相当比2次) 思路:建Trie树,每次建树过程中,后继后继结点就是相同结点需要比较两次ans + val * 2,否则就是不同结点ans + val,建完树就计算完了 代码: #include <cstdio> #include <cstring> const int N = 1005; const int

左儿子右兄弟Trie UVA 11732 strcmp() Anyone?

UVA 11732 strcmp() Anyone?(左儿子右兄弟Trie) ACM 题目地址: UVA 11732 strcmp() Anyone? 题意: 问strcmp函数的==语句执行了几次. UVA 11732 strcmp() Anyone?(左儿子右兄弟Trie) ACM 题目地址: UVA 11732 strcmp() Anyone? 题意: 问strcmp函数的==语句执行了几次. 分析: 大白上的题目. 听说要用左儿子右兄弟的Trie,比较省空间,顺便学了下. 一边inser

uva 11732 - strcmp() Anyone? 不错的Trie题

题解:http://blog.csdn.net/u013480600/article/details/23122503 我的代码一直TLE,,,看了人家的之后,觉得1.链式前向星比较好,2.*depth而不是每过一个节点就计算,这一点很好 我是基本copy别人的代码,自己加了注释,留个记号,随后重写, 这道题同样作为链式前向星的Trie的模板 #include <cstdio> #include <cstring> #include <iostream> using n

UVA 11732 strcmp() Anyone?(左儿子右兄弟Trie)

UVA 11732 strcmp() Anyone?(左儿子右兄弟Trie) ACM 题目地址: UVA 11732 strcmp() Anyone? 题意: 问strcmp函数的==语句执行了几次. 分析: 大白上的题目. 听说要用左儿子右兄弟的Trie,比较省空间,顺便学了下. 开始先建树记录次数,然后再遍历统计,结果错了... 后面参考了Shoutmon巨巨的写法,一边insert一边统计. 代码: /* * Author: illuz <iilluzen[at]gmail.com> *

HDU 4825 tire树

Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)Total Submission(s): 2505    Accepted Submission(s): 1076 Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Ze

Ancient Printer(tire树)

Ancient Printer Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 1511    Accepted Submission(s): 748 Problem Description The contest is beginning! While preparing the contest, iSea wanted to pri