hdu2846(字典树)

http://acm.hdu.edu.cn/showproblem.php?pid=2846

思路:题目属于判断字符串中是否包含子串的问题,对于一般的字典树,用来判断前缀,而这里不能直接这么去建树。在建树的时候将字符串X=X1X2....Xn的分别以X1,X2....Xn开头的后缀子串插入到Trie树中,如此一来就可以判断某个字符串是否被包含在另一个字符串当中。当然,这里还有个问题,比如插入了字符串abab,那么当查找字符串ab时就会重复计数,因此需要多设计一个标识以表示在插入"abab"和"ab"时时同一个字符串即可(是同一个字符串就不需要使计数器加1),因此在Trie树结点中多设计一个商品id来标记。id用来记录最后一个经过此路径上的商品编号,如果要插入的字符串编号同当前节点的编号不同,则计数器加1,并且将当前结点的编号置为要插入的字符串的编号。

#include<iostream>
#include<string.h>
using namespace std;
typedef struct tree
{
	int id;         //最后一次经过此结点的商品ID 
	int num;            //记录包含该结点的单词个数 
	tree *next[26];
}tree;
char s[25];
tree *root=(tree *)malloc(sizeof(tree));
void creat(char str[],int k)
{
	int len=strlen(str);
	tree *p=root,*q;
	for(int i=0;i<len;i++)
	{
		int x=str[i]-'a';
		if(p->next[x]==NULL)
		{
			q=(tree *)malloc(sizeof(tree));
			q->id=k;
			q->num=1;
			for(int j=0;j<26;j++)
				q->next[j]=NULL;
			p->next[x]=q;
		}
		p=p->next[x];
		if(p->id!=k)                             //如果当前结点的商品ID不等于要插入商品的ID,则计数器num++,并且重新置ID的值 
		{
			p->id=k;
			p->num++;
		}
	}
}
int find(char str[])
{
	int len=strlen(str);
	tree *p=root;
	for(int i=0;i<len;i++)
	{
		int x=str[i]-'a';
		if(p->next[x])
			p=p->next[x];
		else
			return 0;
	}
	return p->num;
}
void del(tree *root)
{
	for(int i=0;i<26;i++)
	{
		if(root->next[i])
			del(root->next[i]);
	}
	free(root);
}
int main()
{
	int n,m;
	for(int i=0;i<26;i++)
		root->next[i]=NULL;
	root->num=0;
	root->id=-1;
	scanf("%d",&n);
	for(i=0;i<n;i++)
	{
		scanf("%s",s);
		int len=strlen(s);
		for(int j=0;j<len;j++)              //将字符串X=X1X2...Xn的分别以X1,X2...Xn开头的后缀字符串插入到Tree树中 
		{
			creat(s+j,i);
		}
	}
	scanf("%d",&m);
	while(m--)
	{
		scanf("%s",s);
		printf("%d\n",find(s));
	}
	del(root);
	return 0;
}

 

posted @ 2012-12-13 14:24  紫忆  阅读(1035)  评论(0编辑  收藏  举报