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;
}

浙公网安备 33010602011771号