UVa 11732 strcmp() Anyone?

        题意:这题先展示了一个字符串比较函数strcmp,它的工作原理是这样的,扫描两个字符串的每一位,比较是否相等,如不相等,即可得出结果,如果相等,检查当前位是否为结尾(是结尾表明两个字符串完全相同)。也就是说,两个字符串的比较次数可以这样计算,如果串相等,需比较(长度+1)*2次;否则次数为公共前缀长度*2+1。然后现在有好多字符串,问如果这些字符串两两执行该函数比较,需要比较多少次。

        思路:字典树。随手写了个数组下标代替指针的字典树版本,结果超时了。然后我在此基础上增加了一个链表,把每个节点的所有孩子串起来,还是超时。然后我分析了一下,每个串的长度为1000,有4000个串,也就是最坏的情况下有4000000个节点,每个节点有62个孩子也就是需要4000000*62的空间,不超时也会爆内存(可能因为memset超时)。最后改成了完全以链的形式存储节点的孩子,也就是插入的时候需要沿着链寻找孩子是否已经存在。

        数据结构没问题了,怎么计算比较次数呢?字典树的每一个节点都可以表示一个公共前缀,设具有这样的公共前缀的串的数量为m,那么比较到当前节点时,需要比较的次数就是m*(m-1)/2。递推一下就能算出来了。


#include <iostream>           
#include <stdio.h>           
#include <cmath>           
#include <algorithm>           
#include <iomanip>           
#include <cstdlib>           
#include <string>           
#include <memory.h>           
#include <vector>           
#include <queue>           
#include <stack>           
#include <map>         
#include <set>         
#include <ctype.h>         
#define INF 1<<30       
#define ll long long       
#define max3(a,b,c) max(a,max(b,c))       
#define MAXN 4100000
  
using namespace std;  


struct Trie{
	ll val[MAXN];//具有相同前缀的串的数量 
	ll end[MAXN];//相同串的数量 
	char ch[MAXN];
	int head[MAXN];
	int next[MAXN];
	int sz;
	
	void init(){
		sz=1; val[0]=0;
		memset(head,0,sizeof(head));
		memset(next,0,sizeof(next));
		memset(end,0,sizeof(end));
	}
	
	void insert(char* str){
		int u=0;
		int len=strlen(str);
		val[0]++;
		for(int i=0;i<len;i++){
			
			int t=head[u];
			bool find=false;
			while(t){
				if(ch[t]==str[i]){
					u=t;
					find=1;
					break;
				}
				t=next[t];
			}
			
			if( !find ){
				int v=sz++;
				next[v]=head[u];
				head[u]=v;
				
				val[v]=0;
				ch[v]=str[i];
				head[v]=0;
				u=v;
			}
			val[u]++;
		}
		end[u]++;
	}
	
	ll sear(int u){
		ll re=(val[u]-1)*val[u]/2;
		int t=head[u];
		while(t){
			if(val[t]<=1){
				t=next[t];
				continue;
			}
			re+=(val[t]-1)*val[t]/2;
			re+=(end[t]-1)*end[t]/2;//由于没有存储结束符,需要额外计算一下串相等的情况 
			re+=sear(t);
			
			t=next[t];
		}
		return re;
	}
};

char str[1010];
Trie T;

int main(){
	int n;
	int cas=0;
	while(~scanf("%d",&n)){
		if(!n)break;
		cas++;
		T.init();

		for(int i=1;i<=n;i++){
			scanf("%s",str);
			T.insert(str);
		}
		printf("Case %d: %lld\n",cas,T.sear(0));
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值