题意:给定strcmp函数,输入n个字符串,让你用给定的strcmp函数判断字符比较了多少次。

析:题意不理解的可以阅读原题https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2832

字符串很多,又很长,如果按照题目的意思两两比较,肯定会TLE,所以要用前缀树(Trie)来解决,当然只是用简单的前缀树也会TLE的,

我们必须对其进行优化,看了网上大牛们的,知道要用左儿子右兄弟的方法来优化,说实话,以前还没用过,看了好久才明白是什么个意思,

不是很明白的画个图想一想就会明白的,我采用的是边插入边计算的方法,在每一个分枝都进行计算,然后加和,我们要找每个分枝,

除了最后一个都是2*i+1,最后一个再加上2*i+2。

代码如下:

#include <cstdio>
#include <iostream>
#include <cstring> using namespace std;
typedef long long LL;
const int maxn = 4000 * 1000 + 10;
LL ans = 0;
char s[1010]; struct Trie{
int lson[maxn];
int rbro[maxn];
int val[maxn];
char ch[maxn];
int sz;
void clear(){ sz = 1; lson[0] = rbro[0] = val[0] = 0; ans = 0; } void insert(const char *s){
int u = 0, v, n = strlen(s);
for(int i = 0; i <= n; ++i){
for(v = lson[u]; v; v = rbro[v])
if(s[i] == ch[v]) break;//找到结点 if(!v){//新建结点
v = sz++;
ch[v] = s[i];
lson[v] = 0;//左儿子为空
rbro[v] = lson[u];//结点放在首部
val[v] = 0;//初始化
lson[u] = v;//插入结点
}
ans += (val[u]-val[v]) * (2 * i + 1);//(val[u]-val[v])意思是和v不一样的单词数
if(i == n){
ans += val[v] * (2 * i + 2);
++val[v];
}
++val[u]; u = v;
}
}
}; Trie trie; int main(){
int n, kase = 0;
while(scanf("%d", &n), n){
trie.clear();
for(int i = 0; i < n; ++i){
scanf("%s", s);
trie.insert(s);
} printf("Case %d: %lld\n", ++kase, ans);
}
return 0;
}

下面是大牛Rujia Liu的代码,我基本是根据他的代码写的(因为自己确实是写不出来。。。)

// UVa11732 strcmp() Anyone?
// Rujia Liu
#include<cstring>
#include<vector>
using namespace std; const int maxnode = 4000 * 1000 + 10;
const int sigma_size = 26; // 字母表为全体小写字母的Trie
struct Trie {
int head[maxnode]; // head[i]为第i个结点的左儿子编号
int next[maxnode]; // next[i]为第i个结点的右兄弟编号
char ch[maxnode]; // ch[i]为第i个结点上的字符
int tot[maxnode]; // tot[i]为第i个结点为根的子树包含的叶结点总数
int sz; // 结点总数
long long ans; // 答案
void clear() { sz = 1; tot[0] = head[0] = next[0] = 0; } // 初始时只有一个根结点 // 插入字符串s(包括最后的'\0'),沿途更新tot
void insert(const char *s) {
int u = 0, v, n = strlen(s);
tot[0]++;
for(int i = 0; i <= n; i++) {
// 找字符a[i]
bool found = false;
for(v = head[u]; v != 0; v = next[v])
if(ch[v] == s[i]) { // 找到了
found = true;
break;
}
if(!found) {
v = sz++; // 新建结点
tot[v] = 0;
ch[v] = s[i];
next[v] = head[u];
head[u] = v; // 插入到链表的首部
head[v] = 0;
}
u = v;
tot[u]++;
}
} // 统计LCP=u的所有单词两两的比较次数之和
void dfs(int depth, int u) {
if(head[u] == 0) // 叶结点
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]); // 子树v中选一个串,其他子树中再选一个
ans += sum / 2 * (2 * depth + 1); // 除以2是每种选法统计了两次
for(int v = head[u]; v != 0; v = next[v])
dfs(depth+1, v);
}
} // 统计
long long count() {
ans = 0;
dfs(0, 0);
return ans;
}
}; #include<cstdio>
const int maxl = 1000 + 10; // 每个单词最大长度 int n;
char word[maxl];
Trie trie; int main() {
int kase = 1;
while(scanf("%d", &n) == 1 && n) {
trie.clear();
for(int i = 0; i < n; i++) {
scanf("%s", word);
trie.insert(word);
}
printf("Case %d: %lld\n", kase++, trie.count());
}
return 0;
}

UVa 11732 "strcmp()" Anyone? (左儿子右兄弟前缀树Trie)的更多相关文章

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

    题目地址: option=com_onlinejudge&Itemid=8&category=117&page=show_problem&problem=2832&qu ...

  2. UVA - 11732 "strcmp()" Anyone?左兄弟右儿子trie

    input n 2<=n<=4000 s1 s2 ... sn 1<=len(si)<=1000 output 输出用strcmp()两两比较si,sj(i!=j)要比较的次数 ...

  3. UVA11732 "strcmp()" Anyone?【左儿子右兄弟Trie】

    LINK1 LINK2 题目大意 给你一些字符串,并定义了一个函数(具体见题面) 问你把任意两个字符串放到函数里面得到的值的和是多少 思路 该怎么统计答案呢? 每次考虑当前插入的串和所有已经插入过的串 ...

  4. UVA 11732 - strcmp() Anyone? 字典树

    传送门:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&a ...

  5. Uva 11732 strcmp() Anyone?

    strcmp() Anyone? Time Limit: 2000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu [Subm ...

  6. Vijos p1518 河流 转二叉树左儿子又兄弟

    左儿子又兄弟的转发一定要掌握啊,竞赛必用,主要是降低编程复杂度,省时间.个人觉得状压DP也是为了降低编程复杂度. 方程就不说了,程序应该能看得懂,用的记忆化搜索,方便理解. #include<c ...

  7. UVA 11732 - strcmp() Anyone?(Trie)

    UVA 11732 - strcmp() Anyone? 题目链接 题意:给定一些字符串,要求两两比較,须要比較的总次数(注意.假设一个字符同样.实际上要还要和'\0'比一次,相当比2次) 思路:建T ...

  8. UVa 11732 strcmp()函数(左孩子右兄弟表示法)

    #include<iostream> #include<algorithm> #include<string> #include<cstring> #i ...

  9. UVA 11732 strcmp() Anyone?(Trie的性质)

    strcmp() Anyone? strcmp() is a library function in C/C++ which compares two strings. It takes two st ...

随机推荐

  1. HibernateTemplate使用注意点

    1.  findByExample(vo) 可轻松根据vo的内部数据作为参数查找数据,vo中的基本类型不能为null,同时不支持主键查找. 2. get(vo.class, id) 根据主键来查找数据 ...

  2. 低版本eclipse离线集成svn步骤,亲测有效!!!

    1.下载svn离线版的插件: 百度云盘链接:http://pan.baidu.com/s/1eSnMoHO 密码:6oef 2.解压出来的额目录如下: 3.将features和plugins里面的ja ...

  3. 使用JS获取当前地理位置方法汇总

    使用JS获取当前地理位置方法汇总 投稿:hebedich 字体:[增加 减小] 类型:转载 时间:2014-12-18我要评论 这篇文章主要介绍了使用JS获取当前地理位置方法汇总,需要的朋友可以参考下 ...

  4. 快快快!27个提升效率的iOS开源库推荐(转)

    CSDN移动将持续为您优选移动开发的精华内容,共同探讨移动开发的技术热点话题,涵盖移动应用.开发工具.移动游戏及引擎.智能硬件.物联网等方方面面.如果您想投稿.参与内容翻译工作,或寻求近匠报道,请发送 ...

  5. JSTL标签库学习3-fn

    fn的全称为functions, 就是提供一些方法,函数等. 主要是一些操作字符串的函数. fn:contains(str, str)显示用户浏览器,操作系统.可以从header中获取user-age ...

  6. sublime打开文本时会记忆上次关闭时鼠标停留的位置

    sublime打开文本时会记忆上次关闭时鼠标停留的位置

  7. Kotlin语言学习笔记(4)

    函数 // 函数定义及调用 fun double(x: Int): Int { return 2*x } val result = double(2) // 调用方法 Sample().foo() / ...

  8. Delphi编程实现是否开启“平滑屏幕字体边缘“

    在Windows高级设置中的视觉效果中可以设置是否开启“平滑屏幕字休边缘”,可以通过编程的方式来实现: if SystemParametersInfo(SPI_SETFONTSMOOTHING, 1, ...

  9. 实现溢出文本eclipsis的解决

    实现溢出文本eclipsis的解决:overflow:hidden;text-overflow:ellipsis; white-space:nowrap; 如:<a href="&qu ...

  10. 梯度下降法】三:学习率衰减因子(decay)的原理与Python

    http://www.41443.com/HTML/Python/20161027/512492.html