zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    hdu 5007 水题 (2014西安网赛A题)
    hdu 1698 线段树(成段替换 区间求和)
    poj 3468 线段树 成段增减 区间求和
    hdu 2795 公告板 (单点最值)
    UVaLive 6833 Miscalculation (表达式计算)
    UVaLive 6832 Bit String Reordering (模拟)
    CodeForces 124C Prime Permutation (数论+贪心)
    SPOJ BALNUM (数位DP)
    CodeForces 628D Magic Numbers (数位DP)
    POJ 3252 Round Numbers (数位DP)
  • 原文地址:https://www.cnblogs.com/nanke/p/2047887.html
Copyright © 2011-2022 走看看