您的位置:首页 > 其它

Uva11732 字典树的应用 邻接矩阵(或称左孩子,右兄弟法)保存字典树

2015-04-05 21:59 417 查看
题意 给你一些单词,给你一个字符串比较函数,所有单词比较字典序,问总比较的次数是多少。

思路
大体思路就是两个字符串,设公共前缀的长len,比较次数为2*len+1,若匹配成功则比较次数2*len+2.在字典树上保存,每个边经过的次数和每个节点在该节点结束的单词个数。边建树边计算。

注意树很深,且单词数相对于树深较少,因此选择邻接矩阵保存字典树...(不这么做会被T死的......)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxlen = 1005;
typedef long long ll;

const int maxnode = 4444444;

int lch[maxnode];
int val[maxnode];
int num[maxnode];
int rnext[maxnode];
int type[maxnode];
int sz;
inline int idx(char c){
return c - '0';
}
void init(){
memset(lch,-1,sizeof(lch));
memset(val,0,sizeof(val));
sz = 1;
}
ll insert(char* str)
{
int now = 0;
int n = strlen(str);
bool flag = 0;
ll ret = 0;
for(int i=0;i<n;i++)
{
int p = idx(str[i]);
int e;
if(!flag)
{
for(e=lch[now];e!=-1;e=rnext[e])
{
if(type[e] == p)
break;
}
}
if(flag || e == -1)
{
rnext[sz] = lch[now];
type[sz] = p;
num[sz] = 1;
lch[now] = sz++;
now = sz-1;
flag = 1;
}
else
{
ret += (ll)(2 * num[e]);
num[e]++;
now = e;
}
}
ret += (ll)val[now];
val[now]++;
return ret;
}

int m;
char s[maxlen];
ll ans;
int main()
{
int T = 0;
while(scanf("%d",&m)!=EOF && m)
{
getchar();
T++;
init();
ans = 0;
ans = (ll)m/2*(m-1);
for(int i=0;i<m;i++)
{
gets(s);
ans += insert(s);
}
printf("Case %d: %lld\n",T,ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: