HDU 2222 Keywords Search(AC自动机模板)

Keywords Search

入门题,是看b站的视频入门的,网址:http://www.bilibili.com/video/av6295004/index_2.html#page=2

【题目链接】Keywords Search

【题目类型】AC自动机

&题意:

给出n个串,然后给一篇文章,问这n个串有多少个在文章里面出现过。
trick:n个串可能有相同的,需按照不同串处理。

&代码:
无注释版

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

#define maxn 1000009
#define maxtot 500009

struct Aho {
	struct state {
		int next[26],cnt,fail;
	} sNode[maxtot];
	int size;
	std::queue<int> que;
	void Init() {
		while(que.size()) que.pop();
		for(int i=0; i<maxtot; i++) {
			memset(sNode[i].next,0,sizeof(sNode[i].next));
			sNode[i].fail=sNode[i].cnt=0;
		}
		size=1;
	}
	void Insert(char* S) {
		int n=strlen(S),now=0;
		for(int i=0; i<n; i++) {
			char c=S[i];
			if(!sNode[now].next[c-'a'])
				sNode[now].next[c-'a']=size++;
			now=sNode[now].next[c-'a'];
		}
		sNode[now].cnt++;
	}

	void Build() {
		sNode[0].fail=-1;
		que.push(0);
		while(que.size()) {
			int u=que.front(); que.pop();
			for(int i=0; i<26; i++) if(sNode[u].next[i]) {
					if(u==0) sNode[sNode[u].next[i]].fail=0;
					else {
						int v=sNode[u].fail;
						while(v!=-1) {
							if(sNode[v].next[i]) {
								sNode[sNode[u].next[i]].fail=sNode[v].next[i];
								break;
							}
							v=sNode[v].fail;
						}
						if(v==-1) sNode[sNode[u].next[i]].fail=0;
					}
					que.push(sNode[u].next[i]);
				}
		}
	}

	int Get(int u) {
		int res=0;
		while(u) {
			res+=sNode[u].cnt;
			sNode[u].cnt=0;
			u=sNode[u].fail;
		}
		return res;
	}

	int March(char *S) {
		int n=strlen(S);
		int res=0,now=0;
		for(int i=0; i<n; i++) {
			char c=S[i];
			if(sNode[now].next[c-'a'])
				now=sNode[now].next[c-'a'];
			else {
				int v=sNode[now].fail;
				while(v!=-1&&sNode[v].next[c-'a']==0) v=sNode[v].fail;
				if(v==-1) now=0;
				else now=sNode[v].next[c-'a'];
			}
			if(sNode[now].cnt) {
				res+=Get(now);
			}
		}
		return res;
	}
} aho;
char S[maxn];
int main() {
	// freopen("1.in","r",stdin),freopen("1.out","w",stdout);
	int T;
	scanf("%d",&T);
	while(T--) {
		int N;
		aho.Init();
		scanf("%d",&N);
		for(int i=0; i<N; i++) {
			scanf("%s",S);
			aho.Insert(S);
		}
		aho.Build();
		scanf("%s",S);
		printf("%d
",aho.March(S));
	}
	return 0;
}
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

#define MAX_N 1000009
#define MAX_Tot 500009

//AC自动机结构体
struct Aho {
	//声明节点,注意节点内存在的信息
	struct state {
		int next[26];
		int fail,cnt;
	} stateTable[MAX_Tot];

	//节点数量
	int size;

	//失配指针宽搜的队列
	std::queue<int> que;

	//初始化节点内容和size
	void init() {
		while(que.size()) que.pop();
		for(int i=0; i<MAX_Tot; i++) {
			memset(stateTable[i].next,0,sizeof(stateTable[i].next));
			stateTable[i].fail=stateTable[i].cnt=0;
		}
		size=1;
	}

	//插入单词
	void insert(char *S) {
		int n=strlen(S);
		//now代表现在处理到哪个节点了
		int now=0;
		for(int i=0; i<n; i++) {
			char c=S[i];
			//如果这个节点没有找到路,就新开一条路
			if(!stateTable[now].next[c-'a'])
				stateTable[now].next[c-'a']=size++;
			//把现在的节点赋为将要走的节点
			now=stateTable[now].next[c-'a'];
		}
		//遍历完后走到结束位置,个数++(因为本题有重复模式串的情况)
		stateTable[now].cnt++;
	}

	//构造失配指针
	void build() {
		stateTable[0].fail=-1;
		que.push(0);
		while(que.size()) {
			int u=que.front();
			que.pop();
			//BFS
			for(int i=0; i<26; i++) {
				if(stateTable[u].next[i]) {
					//如果是根节点,那么他的fail指向0
					if(u==0) stateTable[stateTable[u].next[i]].fail=0;
					//否则就一直找到最长后缀,之后再赋值儿子的fail指针
					else {
						int v=stateTable[u].fail;
						while(v!=-1) {
							if(stateTable[v].next[i]) {
								stateTable[stateTable[u].next[i]].fail=stateTable[v].next[i];
								break;
							}
							v=stateTable[v].fail;
						}
						//如果v还是-1,那么fail就只能指向0了
						if(v==-1) stateTable[stateTable[u].next[i]].fail=0;
					}
					//最后push进去,在for里的if里push
					que.push(stateTable[u].next[i]);
				}
			}
		}
	}

	int Get(int u) {
		int res=0;
		while(u) {
			res=res+stateTable[u].cnt;
			stateTable[u].cnt=0;
			u=stateTable[u].fail;
		}
		return res;
	}

	int march(char *S) {
		int n=strlen(S);
		int res=0,now=0;
		for(int i=0; i<n; i++) {
			char c=S[i];
			//如果这条路的next可以走就走这条
			if(stateTable[now].next[c-'a'])
				now=stateTable[now].next[c-'a'];
			//否则就走fail指针的路
			else {
				int p=stateTable[now].fail;
				while(p!=-1&&stateTable[p].next[c-'a']==0) p=stateTable[p].fail;
				//如果始终没找到,就回到根节点
				if(p==-1) now=0;
				//如果找到了,就继续忘下走
				else now=stateTable[p].next[c-'a'];
			}
			if(stateTable[now].cnt) {
				res=res+Get(now);
			}
		}
		return res;
	}
} aho;

int T;

int N;

char S[MAX_N];

int main() {
#ifndef ONLINE_JUDGE
	freopen("1.in","r",stdin),freopen("1.out","w",stdout);
#endif
	scanf("%d",&T);
	while(T--) {
		aho.init();
		scanf("%d",&N);
		for(int i=0; i<N; i++) {
			scanf("%s",S);
			aho.insert(S);
		}
		aho.build();
		scanf("%s",S);
		printf("%d
", aho.march(S));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/s1124yy/p/6398990.html