hdu 2846霸气的字典树

本文详细阐述了一个基于关键词搜索的高效实现方案,通过构建树形结构存储商品名称,并优化了查询过程,使得搜索速度得到显著提升。文章还介绍了如何避免重复计算,以及在构建树时的变通方法,确保了算法的效率和准确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Repository
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1385    Accepted Submission(s): 487


Problem Description
When you go shopping, you can search in repository for avalible merchandises by the computers and internet. First you give the search system a name about something, then the system responds with the results. Now you are given a lot merchandise names in repository and some queries, and required to simulate the process.


Input
There is only one case. First there is an integer P (1<=P<=10000)representing the number of the merchanidse names in the repository. The next P lines each contain a string (it's length isn't beyond 20,and all the letters are lowercase).Then there is an integer Q(1<=Q<=100000) representing the number of the queries. The next Q lines each contains a string(the same limitation as foregoing descriptions) as the searching condition.


Output
For each query, you just output the number of the merchandises, whose names contain the search string as their substrings.


20
ad
ae
af
ag
ah
ai
aj
ak
al
ads
add
ade
adf
adg
adh
adi
adj
adk
adl
aes
5
b
a
d
ad
s



Sample Output

0
20
11
11
2


题意是给你p个源字符串,然后询问Q个目的字符串,询问每个目的字符串时,要你从p个源字符串中找出包含目的字符串的个数。注意当第i个字符串中含有多个目的字符串时,只当作一个。比如源串为ababab abcd 目的串为ab,则输出结果为2,而不是4.所以在建的时候要进行id的判断。此题在传统的建树上面作了变通:比如对字符串abcd进行建树时,不仅要对abcd,还要对bcd,cd,d都进行建树,因为此题中的子串可能是开头,中间或者结尾,所以这样建有利于最后的询问,节省时间。


/*防止重复计算  例如:ababababc ab重复出现了好多次 建立ababababc ab出现了一次 建立abababc ab有出现了一次 建立ababc abc 均出现
这时候本来应该算作是一次的
那么当我们建立了ababababc  再次建立abababc的时候 我们前面要走相同的路线 那么这2个子串是在同一个串中 所以次数就没必要增加了
所以用id标记是否属于同一个字符串 防止重复计算出现次数

*/

#include<stdio.h>
#include<string.h>
#include<malloc.h>
struct haha
{
	int cnt;
	int id;//标记第几个字符串的  防止重复计算 防止重复出现某个串 比如ababababc ab重复出现了好多次
	struct haha *next[26];
}*root;
int ans;
struct haha * creat()
{
	int i;
	struct haha *p;
	p=(struct haha *)malloc(sizeof(struct haha));
	p->cnt=1;
	p->id=-1;
	for(i=0;i<26;i++)
		p->next[i]=NULL;
	return p;
}
void update(char *s,int id)
{
	int d,pos,i;
	struct haha *p;
	p=root;
	d=strlen(s);
	for(i=0;i<d;i++)
	{
        pos=s[i]-'a';
		if(p->next[pos]==NULL)
		{
			p->next[pos]=creat();
			p=p->next[pos];
			p->id=id;
		}
		else
		{
			p=p->next[pos];
			if(p->id!=id)//也就是说这个串的子串没有出现过
			{
				p->id=id;
				p->cnt++;
			}
		}
	} 
}
void query(char *s)
{
	struct haha *p;
	int pos,i,d;
	p=root;
	d=strlen(s);
	for(i=0;i<d;i++)
	{
		pos=s[i]-'a';
		if(p->next[pos]==NULL) return ;
		else
		{
			p=p->next[pos];
		}
	}
	ans=p->cnt;
}
int main()
{
	int i,n,m,k;
	char s[30];
	root=creat();
    scanf("%d",&n);
	for(k=0;k<n;k++)
	{
		scanf("%s",s);
		for(i=0;s[i]!='\0';i++)
			update(&s[i],k);
	}
	scanf("%d",&m);
	while(m--)
	{
		ans=0;
		scanf("%s",s);
		query(s);
		printf("%d\n",ans);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值