UVa 11732 trie好题
来源:互联网 发布:手机mp3变速软件 编辑:程序博客网 时间:2024/04/30 17:40
题目链接
题意:题目给出了标准strcmp()函数的代码,给你n个单词(n <= 4000, len <= 1000, 大小写字母+数字),问你这些单词两两调用strcmp()函数一共比较了多少次。
分析:本题可以用trie做, 但按照一般的方法建字典树的话,会超时。最坏的情况 ,建立新节点的总体时间为 4000 *1000 * 62 == 2.5 * 10^8 很容易超时。
所以一般的建树方法肯定不行,我们必须优化建立新节点的时间。
建树思路:一个节点的62个儿子可以建立成链表,这样,建立一个新节点时就不用初始化其62个儿子节点了,大大优化了时间。
(我的做法比较繁琐,后来网上有位朋友给我分享了更为简单的做法,建树方法跟我一样,计数方法很容易理解,在我的做法后面)
我的做法:把所有的单词插入trie中,然后根据节点的信息计算所有情况。
我是一个字母一个字母统计其比较个数的
情况分析: 逐个字母比较可分为以下几种
1. 两个不同字母的比较, 如 a, b, 算1次
2. 两个相同的字母的比较, 如 a,a, 算2次
3. 一个字母和一个终止符比较 , 如a, \0, 算1次
4. 两个终止符比较,如 \0, \0, 算2次
具体实现看 代码中的dfs
my dfs:
//val记录的是前缀为 根节点走到当前节点所走过字母 的子串个数和。//final记录 串为 根节点走到当前节点所走过字母 的个数和void dfs(int u) { if(u != 1) ans += (LL) p[u].val * (p[u].val - 1); //情况2,统计一次 ans += (LL) p[u].final * (p[u].final - 1); //情况4, 统计一次 LL tmp = (LL) p[u].final * (p[u].val - p[u].final); // 情况3,统计一次 int j = p[u].child; while(j != -1) { tmp += (LL) (p[u].val - p[j].val) * p[j].val; // 这里 情况1 统计两次 和情况3 统计一次 dfs(j); j = p[j].next; } ans += tmp/2; // 情况1,3 都统计了两次,我们必须除以2.}
网友提供的做法:
我们可以一个串一个串的比较,这要方便很多。也避免了多情况的考虑。
直接上别人的代码,注解是我自己写的。
dfs部分代码:
void dfs(int depth, int u) { if(head[u] == 0) // 两个串完全相同(终止符也考虑进去了) depth表示长度 ans += tot[u] * (tot[u] - 1) * depth; else { int sum = 0; for(int v = head[u]; v != 0; v = next[v]) sum += tot[v] * (tot[u] - tot[v]); //统计最后一位字母不同的 串有几对(2个为一对)。 ans += sum / 2 * (2 * depth + 1); //相同字母有depth个,要算2次,所以 sum * 2*depth // +1 加上最后一位是不同字母的个数。 for(int v = head[u]; v != 0; v = next[v]) dfs(depth+1, v); } }
my code:
#include <cstdio>#include <cstring>#include <cctype>#define LL long longstruct node {int val, final, child, next;int next_char, child_char;}p[4002 * 1002];int tot, n;LL ans;int idx(char c) { // translate the character into range 0-61.if(isupper(c)) return c-'A';if(islower(c)) return c-'a'+26;return c-'0'+52;}void insert(char *s) {int u = 1, i, j; // "u" means current nodep[u].val++;for(i = 0; s[i]; i++) {int k = idx(s[i]);if(p[u].child == -1) { // if current node has no children, create one.p[u].child = ++tot;p[u].child_char = k;p[tot].next = -1; p[tot].child = -1;p[tot].val = p[tot].final = 0;u = tot;}else if(p[u].child_char > k) { // if the first child is too big, we need to create a new first child.p[++tot].next = p[u].child; p[tot].next_char = p[u].child_char;p[u].child = tot; p[u].child_char = k;p[tot].child = -1;p[tot].val = p[tot].final = 0;u = tot;}else if(p[u].child_char == k) // if the first child exactly matches, just descend.u = p[u].child;else { // walk the list of children to find the matching one, create one if needed.j = p[u].child;while(p[j].next != -1 && p[j].next_char < k) j = p[j].next;if(p[j].next != -1 && p[j].next_char == k) u = p[j].next;else {p[++tot].next = p[j].next;p[tot].next_char = p[j].next_char;p[j].next = tot; p[j].next_char = k;p[tot].child = -1;p[tot].val = p[tot].final = 0;u = tot;}}p[u].val++;}p[u].final++;}void dfs(int u) { // every pair of words that reaches here produces two comparisons.if(u != 1) ans += (LL) p[u].val * (p[u].val - 1); // pay attention the root, we needn't add it.ans += (LL) p[u].final * (p[u].final - 1);// every pair of words that differs exactly here produces one more comparison.LL tmp = (LL) p[u].final * (p[u].val - p[u].final); int j = p[u].child;while(j != -1) {tmp += (LL) (p[u].val - p[j].val) * p[j].val;dfs(j);j = p[j].next;}ans += tmp/2; }char s[1005];int main() {int i, j, cas = 1;while( ~scanf("%d", &n) && n) {tot = 1;p[tot].child = p[tot].next = -1;p[tot].val = p[tot].final = 0;while(n--) {scanf("%s", s);insert(s);}ans = 0;dfs(1);printf("Case %d: %lld\n", cas++, ans);}return 0;}
- UVa 11732 trie好题
- UVa 11732 strcmp()函数 trie
- UVA 11732 strcmp() Anyone (Trie)
- UVA 11732 - strcmp() Anyone?(Trie)
- UVA 11732 strcmp() Anyone? (Trie)
- uva 11732 - strcmp() Anyone? 不错的Trie题
- UVA 11732 strcmp() Anyone?(trie)
- UVA 11732 strcmp() Anyone?(字典树Trie)
- Trie (前缀树)uva 11732
- UVa 11732 - strcmp() Anyone? (Trie + 邻接表)
- UVA 11732 "strcmp()" Anyone? (Trie)
- UVA 11732 trie树 + 插入式比较
- (考前水题) UVa 11488 Trie树
- uva 10282 Trie树
- uva 1401 dp+Trie
- UVA 10391 trie树
- uva 10125 - Sumsets好题
- UVa 11235 RMQ好题
- linux 服务器之间拷贝文件
- 解决数据库质疑问题
- U-Boot启动过程--详细版的完全分析
- 2012总结
- 用display做导航栏
- UVa 11732 trie好题
- 编程学习(四)----c++总体概览(一)
- VC/MFC读取BMP文件并显示
- (转)Android通过SharedPreferences实现数据库访问共享
- cocos2d-x初探学习笔记(6)--场景间切换效果
- 自动提取人脸关键特征点
- 工作总结
- 倒排索引
- Jsp+Servlet+JDBC 登录