HDU 2222 Keywords Search题解与翻译

【题目大意】给出多组数据(第一行输入的N),每组数据第一行给出要录入的单词数,最后一行给出文章,要求计算录入的单词在文章中出现了多少次。

【分析】很裸的AC自动机。首先建一棵Trie树,再用类似于KMP的next数组一样对每一个Trie树结点求出对应的失败指针,从而在每次失败后,在每个录入单词中找一个最优的串的合适的位置继续进行匹配,最后对文章进行匹配即可。

→为方便查阅,给出链接:

      Trie树百度百科:http://baike.baidu.com/view/1436495.htm

      KMP详解:http://blog.csdn.net/u011400953/article/details/9324095

【原题地址】http://acm.hdu.edu.cn/showproblem.php?pid=2222

【代码】

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define MAX 500001
struct TREE{int fail,son[26+6],num;};
TREE trie[MAX];
int CASE,N,node_num=0;
int ans=0;
char NOW1[101],NOW2[1000001];
void tree_clear()
{
	ans=0;
	node_num=0;
	for(int i=0;i<=N;i++)
	{
		  trie[i].fail=0;
		  trie[i].num=0;
		  for(int j=0;j<=26;j++)
		        trie[i].son[j]=0;
	}
}
void insect(char *NOW)
{
	int now=0,len=strlen(NOW);
	for(int i=0;i<len;i++)
	{
		  if(!trie[now].son[(int)NOW[i]-(int)'a'])
		        trie[now].son[(int)NOW[i]-(int)'a']=++node_num;
		  now=trie[now].son[(int)NOW[i]-(int)'a'];
	}
	trie[now].num++;//=1 ?
}
void build_fail()
{
	queue<int> q;
	int now=0;
	for(int i=0;i<26;i++)
	      if(trie[now].son[i])
	      {
	            q.push(trie[now].son[i]);
	            trie[trie[now].son[i]].fail=0;
	      }
	while(!q.empty())
	{
		  int point,now_fail;
		  now=q.front();
		  q.pop();
		  for(int i=0;i<26;i++)
		        if(point=trie[now].son[i])
		        {
		  	          now_fail=trie[now].fail;
		  	          while(now_fail && !trie[now_fail].son[i])
		  	    	         now_fail=trie[now_fail].fail;
				      trie[point].fail=trie[now_fail].son[i];
				      q.push(point);
		        }
	}
}
void find(char *NOW)
{
	int len=strlen(NOW),now=0,use=0;
	for(int i=0;i<len;i++)
	{
		  while(now && !trie[now].son[(int)NOW[i]-(int)'a'])
		        now=trie[now].fail;
		  now=trie[now].son[(int)NOW[i]-(int)'a'];
		  use=now;
		  while(use)
		  {
		  	   ans+=trie[use].num;
		  	   trie[use].num=0;
		  	   use=trie[use].fail;
		  }
	}
}
int main()
{
	//freopen("test.in","r",stdin);
	//freopen("test.out","w",stdout);
	scanf("%d",&CASE);
	for(int i=1;i<=CASE;i++)
	{
	      scanf("%d",&N);
		  tree_clear();
		  for(int j=1;j<=N;j++)
		  {
		  	    scanf("%s",NOW1);
		  	    insect(NOW1);
		  }
		  build_fail();
		  scanf("%s",NOW2);
		  find(NOW2);
		  printf("%d\n",ans);
	}
	return 0;
}


 转载注明出处:http://blog.csdn.net/u011400953

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值