pku1816 Wild Words(字典树+DFS+并查集)

这题目郁闷死了,因为一些小错误,搞了半天,不过,要注意的东西真的很多哦

题意是找出单词的所有符号要求的匹配模式,首先将模式存入字典树中,再用单词进行查找

需要注意的问题:看到输出的sample也应该知道了,一个单词有多种匹配模式,用一个单词进行遍历时,到达同一个单词的结尾,却可能经历了不同的匹配模式,所以这里用了并查集来保存

具体的,还是结合代码吧,比较好解释

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
struct node
{
	int num;//保存模式的编号
	node *next[28];
};
node *root;
int cou[400005],f[100005],len,k;//cou记录所有的匹配模式,f记录到达同一个节点的模式的编号,将这些模式关联起来
char key[10],str[25];
void insert(char *s,int d)//插入过程基本和之前没什么区别,就是多了俩个指针
{
	node *p=root;
	for(;*s!='\0';s++)
	{
		if(*s>='a'&&*s<='z')
		{
			int id=*s-'a';
			if(p->next[id]!=NULL)
			{
				p=p->next[id];
			}
			else {
				p->next[id]=new node();
				p->next[id]->num=-1;
				p=p->next[id];
			}
		}
		else if(*s=='?')
		{
			if(p->next[26]!=NULL)
			{
				p=p->next[26];
			}
			else 
			{
				p->next[26]=new node();
				p->next[26]->num=-1;
				p=p->next[26];
			}
		}
		else {
			if(p->next[27]!=NULL)
				p=p->next[27];
			else {
				p->next[27]=new node();
				p->next[27]->num=-1;
				p=p->next[27];
			}
		}
	}
	if(p->num==-1)
		p->num=d;
	else //出现相同的模式,用并查集将编号关联起来
	{
		f[d]=p->num;
		p->num=d;
	}
}
void dfs(node *p,int d)
{
	if(str[d]==0)//所查的单词到达末尾
	{
		if(p->num!=-1)//存在匹配的模式
		{
			k++;
			cou[k]=p->num;
		}
		while(p->next[27]!=NULL)//以“*”结尾的模式十分特殊,因为“*”既可以表示一个,多个,也可以表示没有,所有一直查找后面是否还有以*号结尾的模式
		{
			if(p->next[27]->num!=-1)
			{
				k++;
				cou[k]=p->next[27]->num;
			}
			p=p->next[27];
		}
		return ;
	}
	if(p->next[str[d]-'a']!=NULL)
		dfs(p->next[str[d]-'a'],d+1);
	if(p->next[26]!=NULL)//只要是存在“?",都可以进入搜索
		dfs(p->next[26],d+1);
	if(p->next[27]!=NULL)//*号还是比较麻烦
	{
		for(int i=d;i<=len;i++)//这里i从d开始,包含了三种情况,*号表示为空,一个,还有多个,用DFS原来如此巧妙呀,
			//而且很好理解,注意,这里的i<=len,'='号不能省呀,注意深搜的退出条件
			dfs(p->next[27],i);
	}
}
int main()
{
	int i,j,ans,n,m;
	while(scanf("%d %d",&n,&m)!=EOF)
	{
		for(i=0;i<n;i++)
			f[i]=i;
		root=new node();
		root->num=-1;
		for(i=0;i<n;i++)
		{
			scanf("%s",key);
			insert(key,i);
		}
		while(m--)
		{
			scanf("%s",str);
			len=strlen(str);
			k=0;
			dfs(root,0);
			if(k==0)//一个都没找到
			{
				printf("No match\n");
			}
			else {
				ans=k;
				for(i=1;i<=ans;i++)
				{
					j=cou[i];
					while(f[j]!=j)//找出与该模式关联的模式,存入cou中
					{
						k++;
						cou[k]=f[j];
						j=f[j];
					}
				}
				sort(cou+1,cou+k+1);//悲剧就在这里了,k忘记加一了,可是测试例子居然没错呀
				cou[0]=-1;
				for(i=1;i<=k;i++)
				{
					if(cou[i]!=cou[i-1])//注意不要输出相同的
						printf("%d ",cou[i]);//最后一个输出多了一个空格,但还是A 了,省了不少麻烦
				}
				printf("\n");
			}
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/nanke/p/2047887.html