HDU - 2222 Keywords Search AC自动机

不问归期 提交于 2019-11-26 16:58:01

题目链接:https://vjudge.net/problem/HDU-2222

题意:n个字符串在文本串出现的总次数

学习博客:https://blog.csdn.net/bestsort/article/details/82947639

在为下一个节点找fail的时候:

 有这个节点,失配后指向父亲失配后指向的那个节点的下一个 
 没有这个节点,直接指向失配后指向的那个节点 

实现方式:bfs

#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
struct AC {
	int tree[N][26];
	int fail[N];
	int val[N];
	int tot;
	void init(int x) {
		tot = 0;
		for(int i = 0; i <= x; i++) {
			fail[i] = 0;
			val[i] = 0;
			for(int j = 0; j < 26; j++)
				tree[i][j] = 0;
		}
	}
	void insert(char *str) {
		int len = strlen(str);
		int p = 0, op;
		for(int i = 0; i < len; i++) {
			op = str[i] - 'a';
			if(tree[p][op] == 0)
				tree[p][op] = ++tot;
			p = tree[p][op];
		}
		val[p]++;
	}
	void getfail() {
		queue<int> q;
		for(int i = 0; i < 26; i++) {
			if(tree[0][i]) {
				fail[tree[0][i]] = 0;
				q.push(tree[0][i]);
			}
		}
		int now;
		while(!q.empty()) {
			now = q.front(); q.pop();
			for(int i = 0; i < 26; i++) {
				if(tree[now][i]) { // 有这个节点,失配后指向父亲失配后指向的那个节点的下一个 
					fail[tree[now][i]] = tree[fail[now]][i];
					q.push(tree[now][i]);
				} else { // 没有这个节点,直接指向失配后指向的那个节点 
					tree[now][i] = tree[fail[now]][i];
				}
			}
		}
	}
	int query(char *str) {
		int p = 0, res = 0;
		int len = strlen(str);
		for(int i = 0; i < len; i++) {
			p = tree[p][str[i] - 'a'];
			for(int j = p; j && val[j] != -1; j = fail[j]) { // 不断找fail 
				res += val[j];
				val[j] = -1;
			}
		}
		return res;
	}
}A;
int n;
char s[N * 10];
int main() {
	int T;
	scanf("%d", &T);
	while(T--) {
		scanf("%d", &n);
		A.init(n * 50);
		for(int i = 1; i <= n; i++) {
			scanf("%s", s);
			A.insert(s);
		}	
		A.getfail();
		scanf("%s", s);
		printf("%d\n", A.query(s)); 
	}
	return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!