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;

}

 

你可能感兴趣的:(HDU)