1036 : Trie图 (AC自动机)

题目大意: 输入 n 个目标单词和一个文本串,判断文本串中是否存在某些目标单词。

思路 赤裸裸的 AC自动机。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
#define INF 0x7fffffff

int ch[1000010][26],f[1000010],last[1000010],val[1000010],nz,found;
char s[1000000],T[1000010];

void insert(){
	int i,j,u = 0,len = strlen(s);
	for(i=0; i<len; i++){
		int v = s[i] - 'a';
		if(!ch[u][v]){
			memset(ch[nz],0,sizeof(ch[nz]));
			val[nz] = 0;
			ch[u][v] = nz ++;
		}
		u = ch[u][v];
		val[u] = 0;
	}
	val[u] = 1;
}

void getFail(){
	int i,j,n;
	queue<int> Q;
	while(!Q.empty())
	    Q.pop();
	f[0] = 0;
	for(int c =0; c<26; c++){
		int u = ch[0][c];
		if(u){
			f[u] = 0;
			last[u] = 0;
			Q.push(u);	
		}
	}
	while(!Q.empty()){
		int r = Q.front();
		Q.pop();
		for(int c=0; c<26; c++){
			int u = ch[r][c];
			if(!u)
			    continue;
			Q.push(u);
			int v = f[r];
			while(v && !ch[v][c])
			    v = f[v];
			f[u] = ch[v][c];
			last[u] = val[f[u]] ? f[u] : last[f[u]];
		}
	}
}

void find(){
	int i,j,len = strlen(T),u = 0;
	for(i=0; i<len; i++){
		int v = T[i] - 'a';
		while(u && !ch[u][v]) u = f[u];
		u = ch[u][v];
		if(val[u]){
			found = 1;
			return ;
		} 
		else if(last[u]){
			found = 1;
			return ;
		}
	}
}

int main(){
	int i,n;
	while(scanf("%d",&n) == 1){
		found = 0;
		memset(val,0,sizeof(val));
		memset(ch[0],0,sizeof(ch[0]));
		nz = 1;
		for(i=0;i<n;i++){
			scanf("%s",s);
			insert();
		}
		scanf("%s",T);
		getFail();
		find();
		if(!found)
		    printf("NO\n");
		else
		    printf("YES\n");
	}

	return 0;
}
posted @ 2015-09-04 18:05  阿文的博客  阅读(175)  评论(0编辑  收藏  举报