UVA - 11732 "strcmp()" Anyone? (字典树的处理)
来源:互联网 发布:mac万能钥匙怎么连接 编辑:程序博客网 时间:2024/04/29 08:06
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=28438
1.对于这个题我们可以用字典树来做,我们可以统计前缀相同的字母个数,对于前缀相同的单词每个字母要比较两次(包括‘\0’)。又因为要把任意两个单词相比较。所以相同字母的比较次数为2*val[i[*(val[i]-1).对于不相等的单词,由题意可得这个仅比较一次,即同所得单词相比较次数为(n-val[i])*val[i].对所有的点求和即可。因为这样计数每个都多统计了一次,所以对这个答案要除以2.
2.关于字典树,我们可以用链表来写。也可以用二维数组实现。也可以用左儿子右兄弟的方式来实现。
指针字典树:
struct trie
{
trie *next[28];
int val;
};
trie *root;
inline trie *newnode()//申请字符节点
{
trie *t;
t=(trie*)malloc(sizeof (trie) );
memset(t,0,sizeof (trie) );
return t;
}
{
trie *next[28];
int val;
};
trie *root;
inline trie *newnode()//申请字符节点
{
trie *t;
t=(trie*)malloc(sizeof (trie) );
memset(t,0,sizeof (trie) );
return t;
}
void ins(trie *s,char x[])//字典树插入字符
{
{
int i;
trie *t;
for(i=0;x[i]!='\0';i++)
{
trie *t;
for(i=0;x[i]!='\0';i++)
{
if(s->next[x[i]-'a'])
{
s=s->next[x[i]-'a'];
}
else{
t=newnode();
s->next[x[i]-'a']=t;
s=t;
}
s->val++;//统计项
}
}
{
s=s->next[x[i]-'a'];
}
else{
t=newnode();
s->next[x[i]-'a']=t;
s=t;
}
s->val++;//统计项
}
}
二维数组的字典树:
struct trie
{
public:
int ch[maxn][30];//ch储存字符节点
int val[maxn];
int sz=1;
void tt() { sz=1; memset(ch[0],0,sizeof(ch[0]) ); };
int idx(char c) { return c-'a'; }//字符表转换
{
public:
int ch[maxn][30];//ch储存字符节点
int val[maxn];
int sz=1;
void tt() { sz=1; memset(ch[0],0,sizeof(ch[0]) ); };
int idx(char c) { return c-'a'; }//字符表转换
void insert_(char *s2,int v)//如果该字符不存在于字典树中,则初始化结点。
{
int u=0,n=strlen(s2);
for(int i=0;i<n;i++)
{
int c=idx(s2[i]);
if(!ch[u][c])
{
memset(ch[sz],0,sizeof(ch[sz]));
val[sz]=0;
ch[u][c]=sz++;
}
u=ch[u][c];//向下访问
}
val[u]=v;//统计项
};
{
int u=0,n=strlen(s2);
for(int i=0;i<n;i++)
{
int c=idx(s2[i]);
if(!ch[u][c])
{
memset(ch[sz],0,sizeof(ch[sz]));
val[sz]=0;
ch[u][c]=sz++;
}
u=ch[u][c];//向下访问
}
val[u]=v;//统计项
};
}
左儿子右兄弟的表示方法:
class trie{
public:
int head[maxn],next[maxn],val[maxn],sz;//head[i]表示i结点的左孩子,next[i]表示i节点的右兄弟
char ch[maxn];
void init(){ sz=1,ch[0]=val[0]=head[0]=next[0]=0;}//值为0表示后面没有节点
void ins(char *ss)//字符的插入
{
int v,u=0,len=strlen(ss);
for(int i=0;i<=len;i++)
{
int f=0;
for( v=head[u];v!=0;v=next[v])/*先在当前兄弟里面找到是否有与
{
int f=0;
for( v=head[u];v!=0;v=next[v])/*先在当前兄弟里面找到是否有与
s[i]相同的节点,没有则创建一个兄弟节点。有则继续向下遍历。*/
{
if(s[i]==ch[v])
{
f=1;
break;
}
}
if(!f)//没找到与s[i]相等的节点,把这个字符插入到最左边,即这个成为u节点的左儿子。则之前的左儿子就变成v的右兄弟。v没有左二子。
{
v=sz++;
val[v]=0;
ch[v]=s[i];
next[v]=head[u];
head[u]=v;
head[v]=0;
}
u=v;//向下遍历
val[v]++;
}
{
if(s[i]==ch[v])
{
f=1;
break;
}
}
if(!f)//没找到与s[i]相等的节点,把这个字符插入到最左边,即这个成为u节点的左儿子。则之前的左儿子就变成v的右兄弟。v没有左二子。
{
v=sz++;
val[v]=0;
ch[v]=s[i];
next[v]=head[u];
head[u]=v;
head[v]=0;
}
u=v;//向下遍历
val[v]++;
}
}
}t;
对于这三种表示方法,用链表动态申请内存很明显要复杂的多。而对于第二种每次申请一个节点都需要将其相应的子节点初始化完。这样初始化既耗费一定的时间。数组的粗存对于内存的占用可能也有消耗(这题用第二种写一直是RE,不知道是怎么回事。然后百度看到了第三种写法,1A)。感觉第三种写法的比上面的还是挺优化的了。在空间时间上都存在优化了。
AC:
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<stdio.h>
using namespace std;
#define ll long long int
#define maxn 8000008
const int mod=20071027;
char s[maxn];
class trie
{
public:
int head[maxn],next[maxn],val[maxn],sz;
char ch[maxn];
void init(){ sz=1,ch[0]=val[0]=head[0]=next[0]=0;}
void ins(char *ss)
{
int v,u=0,len=strlen(ss);
#include<iostream>
#include<cmath>
#include<map>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<stdio.h>
using namespace std;
#define ll long long int
#define maxn 8000008
const int mod=20071027;
char s[maxn];
class trie
{
public:
int head[maxn],next[maxn],val[maxn],sz;
char ch[maxn];
void init(){ sz=1,ch[0]=val[0]=head[0]=next[0]=0;}
void ins(char *ss)
{
int v,u=0,len=strlen(ss);
for(int i=0;i<=len;i++)
{
int f=0;
for( v=head[u];v!=0;v=next[v])
{
if(s[i]==ch[v])
{
f=1;
break;
}
}
if(!f)
{
v=sz++;
val[v]=0;
ch[v]=s[i];
next[v]=head[u];
head[u]=v;
head[v]=0;
}
u=v;
val[v]++;
}
{
int f=0;
for( v=head[u];v!=0;v=next[v])
{
if(s[i]==ch[v])
{
f=1;
break;
}
}
if(!f)
{
v=sz++;
val[v]=0;
ch[v]=s[i];
next[v]=head[u];
head[u]=v;
head[v]=0;
}
u=v;
val[v]++;
}
}
}t;
int main(void)
{
int n;
ll ans;
int k=0;
while(scanf("%d",&n)!=EOF)
{
t.init();
if(n==0) break;
ans=0;
ll sum1=0;
ll sum2=0;
for(int i=0;i<n;i++)
{
scanf("%s",s);
t.ins(s);
}
for(int i=1;i<t.sz;i++)
{
sum1+=t.val[i]*(t.val[i]-1);
if(t.ch[i]=='\0')
sum2+=(n-t.val[i])*t.val[i] ;
}
printf("Case %d: %lld\n",++k,sum1+sum2/2);
}
int main(void)
{
int n;
ll ans;
int k=0;
while(scanf("%d",&n)!=EOF)
{
t.init();
if(n==0) break;
ans=0;
ll sum1=0;
ll sum2=0;
for(int i=0;i<n;i++)
{
scanf("%s",s);
t.ins(s);
}
for(int i=1;i<t.sz;i++)
{
sum1+=t.val[i]*(t.val[i]-1);
if(t.ch[i]=='\0')
sum2+=(n-t.val[i])*t.val[i] ;
}
printf("Case %d: %lld\n",++k,sum1+sum2/2);
}
}
0 0
- UVA - 11732 "strcmp()" Anyone? (字典树的处理)
- UVA 11732 "strcmp()" Anyone?(字典树)
- Uva 11732 "strcmp()" Anyone? (字典树)
- UVA 11732 - strcmp() Anyone? 字典树
- UVA 11732 strcmp() Anyone?(字典树Trie)
- uva 11732 strcmp() Anyone? 字典树
- uva 11732 - strcmp() Anyone?(字典树)
- uva 11732 "strcmp()" Anyone?(字典树)
- UVA 11732 "strcmp()" Anyone? 字典树(数组实现)
- UVA “strcmp()" Anyone?【字典树数组链表版】
- Uva 11732 "strcmp()" Anyone? ——空间优化的字典树
- Uva-11732-strcmp() Anyone?
- Uva 11732 strcmp() Anyone?
- uva 11732 - strcmp() Anyone?
- UVa:11732 strcmp() Anyone?
- UVA - 11732 strcmp() Anyone?
- UVa 11732 - strcmp() Anyone?
- UVa 11732 strcmp() Anyone?
- Linux学习笔记--打包压缩命令
- C++中多态的实现原理
- 6.CardView
- MySql 64位 windows下环境配置
- 自定义控件三部曲之动画篇(一)——alpha、scale、translate、rotate、set的xml属性及用法
- UVA - 11732 "strcmp()" Anyone? (字典树的处理)
- Android开发---Vitamio框架的实战应用
- ubuntu the system is running in low-graphics mode 解决办法
- iOS开发-多线程开发之线程安全篇
- 14. Longest Common Prefix
- iOS 截取原型图片
- 正则表达式匹配任意字符(包括换行符)的写法
- C++笔记 explicit构造函数
- HDU 1226 超级密码(BFS)