HDU2222 Keywords Search AC自动机

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - HDU2222


题意概括

   先给出一些模式串,然后给出一个母串,统计先前给出的模式串中,有多少个在母串中出现。多组数据。


题解

  AC自动机模板题。

  首先根据输入数据构建AC自动机。

  然后对于每一位,沿着fail指针走,全部统计并累加。

  有一个小小的优化,就是走过的都标记为-1,下次碰到-1就不走了。因为如果这个节点的标记为-1,那么它的fail一再在它之前就标记成-1了(即统计过了)。


代码

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=10005,L1=55,L2=1000005;
int T,n,cnt;
char ch[L1],str[L2];
struct Trie{
	int e,fail,Next[26];
	void init(){
		e=fail=0;
		memset(Next,0,sizeof Next);
	}
}tree[N*L1];
void AC_init(){
	cnt=1;
	tree[0].init();
	tree[1].init();
	for (int i=0;i<26;i++)
		tree[0].Next[i]=1;
}
void build(char ch[]){
	int rt=1,t,len=strlen(ch);
	for (int i=0;i<len;i++){
		t=ch[i]-'a';
		if (!tree[rt].Next[t]){
			tree[++cnt].init();
			tree[rt].Next[t]=cnt;
		}
		rt=tree[rt].Next[t];
	}
	tree[rt].e++;
}
int q[N*L1],head,tail;
void build_AC(){
	int rt,k,son;
	head=tail=0;
	tree[0].fail=1,tree[1].fail=0;
	q[++tail]=1;
	while (head<tail){
		rt=q[++head];
		for (int i=0;i<26;i++){
			son=tree[rt].Next[i];
			if (!son){
				tree[rt].Next[i]=tree[tree[rt].fail].Next[i];
				continue;
			}
			k=tree[rt].fail;
			while (!tree[k].Next[i])
				k=tree[k].fail;
			tree[son].fail=tree[k].Next[i];
			q[++tail]=son;
		}
	}
}
int solve(){
	int rt=1,t,len=strlen(str);
	int ans=0;
	for (int i=0;i<len;i++){
		t=str[i]-'a';
		rt=tree[rt].Next[t];
		int k=rt;
		while (~tree[k].e){
			ans+=tree[k].e;
			tree[k].e=-1;
			k=tree[k].fail;
		}
	}
	return ans;
}
int main(){
	scanf("%d",&T);
	while (T--){
		scanf("%d",&n);
		AC_init();
		for (int i=0;i<n;i++){
			scanf("%s",ch);
			build(ch);
		}
		build_AC();
		scanf("%s",str);
		printf("%d\n",solve());
	}
	return 0;
}

  

posted @ 2017-11-02 21:28  zzd233  阅读(230)  评论(0编辑  收藏  举报