【模板】AC自动机

点击查看代码
#include <stdio.h>
#include <queue>
#include <string.h>
enum {
	the_size = 1000010
};
class AC_automaton {
	private : 
		struct TRIE {
			int fail;//fail指针;
			int cnt;//此节点模式串数;
			int sid[26];//子节点;
		} trie[the_size];
		int tot, ROOT;
		std :: queue<int> q;
		#define tr(id,choice) trie[id].sid[choice]
		#define fail(id) trie[id].fail
		#define cnt(id) trie[id].cnt
		void AC_ins(char *pattern) {
			int u = ROOT;
			for(int i = 0;pattern[i];++i) {
				if(!tr(u,pattern[i]-'a')) 
					tr(u,pattern[i]-'a') = ++tot;
				u = tr(u,pattern[i]-'a');
			}
			cnt(u)++;
		}
		void AC_con() {
			for(int i = 0;i < 26;++i) 
				if(tr(ROOT,i)) q.push(tr(ROOT,i));
			while(!q.empty()) {
				int u = q.front();
				q.pop();
				for(int i = 0;i < 26;++i) {
					if(tr(u,i)) {
						fail(tr(u,i)) = tr(fail(u),i);
						q.push(tr(u,i));
					} else {
						tr(u,i) = tr(fail(u),i);
					}
				}
			}
		}
		int AC_qry(char *text) {
			int u = 0, res = 0;
			for(int i = 0;text[i];++i) {
				u = tr(u,text[i]-'a');
				for(int j = u;j&&cnt(j) != -1;j = fail(j)) {
					res += cnt(j);
					cnt(j) = -1;
				}
			}
			return res;
		}
		#undef tr
		#undef fail
		#undef cnt
	public : 
		void init() {
			trie[tot].fail = trie[tot].cnt = 0;
			memset(trie[tot].sid,0,sizeof(trie[tot].sid));
			while(tot--) {
				trie[tot].fail = trie[tot].cnt = 0;
				memset(trie[tot].sid,0,sizeof(trie[tot].sid));
			}
			ROOT = 0;
		}
		void Insert(char *pattern) {
			AC_ins(pattern);
		}
		void Construct() {
			AC_con();
		}
		int Query(char *text) {
			return AC_qry(text);
		}
} automaton;
char tmp[the_size];
int n;
void automation() {
	scanf("%d",&n);
	for(int i = 1;i <= n;++i) {
		scanf("%s",tmp);
		automaton.Insert(tmp);
	}
	scanf("%s",tmp);
	automaton.Construct();
	printf("%d",automaton.Query(tmp));
	return;
}
signed main() {
	automation();
}
点击查看代码
#include <stdio.h>
#include <queue>
#include <string.h>
enum {
	the_size = 16384
};
class AC_automaton {
	private : 
		struct TRIE {
			int fail;//fail指针;
			int sid[26];//子节点;
			int value, index;
		} trie[the_size];
		int tot, ROOT, cnt[the_size];
		std :: queue<int> q;
		#define tr(id,choice) trie[id].sid[choice]
		#define fail(id) trie[id].fail
		#define val(id) trie[id].value
		#define ind(id) trie[id].index
		void AC_ins(char *pattern,int index) {
			int u = ROOT;
			for(int i = 0;pattern[i];++i) {
				if(!tr(u,pattern[i]-'a')) 
					tr(u,pattern[i]-'a') = ++tot;
				u = tr(u,pattern[i]-'a');
			}
			ind(u) = index;
		}
		void AC_con() {
			for(int i = 0;i < 26;++i) 
				if(tr(ROOT,i)) q.push(tr(ROOT,i));
			while(!q.empty()) {
				int u = q.front();
				q.pop();
				for(int i = 0;i < 26;++i) {
					if(tr(u,i)) {
						fail(tr(u,i)) = tr(fail(u),i);
						q.push(tr(u,i));
					} else {
						tr(u,i) = tr(fail(u),i);
					}
				}
			}
		}
		int AC_qry(char *text) {
			int u = 0, res = 0;
			for(int i = 0;text[i];++i) {
				u = tr(u,text[i]-'a');
				for(int j = u;j;j = fail(j))
					val(j)++;
			}
			for(int i = 0;i <= tot;++i) {
				if(ind(i)) {
					res = std :: max(res,val(i));
					cnt[ind(i)] = val(i);
				}
			}
			return res;
		}
		#undef tr
		#undef fail
		#undef ind
		#undef val
	public : 
		void init() {
			memset(cnt,0,sizeof(cnt));
			trie[tot].fail = 0;
			trie[tot].value = trie[tot].index = 0;
			memset(trie[tot].sid,0,sizeof(trie[tot].sid));
			while(tot--) {
				trie[tot].fail = 0;
				trie[tot].value = trie[tot].index = 0;
				memset(trie[tot].sid,0,sizeof(trie[tot].sid));
			}
			//没想到这里错了,tot会减到-1;
			tot = ROOT = 0;
		}
		void Insert(char *pattern,int index) {
			AC_ins(pattern,index);
		}
		void Construct() {
			AC_con();
		}
		int Query(char *text) {
			return AC_qry(text);
		}
		int icnt(int i) {
			return cnt[i];
		}
		void out() {
			printf("%d :: \n",tot);
			for(int i = 0;i <= tot;++i) 
				printf("%d %d %d\n",trie[i].fail,trie[i].index,trie[i].value);
		}
} automaton;
char tmp[256][128];
char text[1000020];
int n;
void automation() {
	while(scanf("%d",&n) != EOF) {
		if(!n) break;
		automaton.init();
		for(int i = 1;i <= n;++i) {
			scanf("%s",tmp[i]);
			automaton.Insert(tmp[i],i);
		}
		automaton.Construct();
		scanf("%s",text);
		//automaton.out();
		int ans = automaton.Query(text);
		printf("%d\n",ans);
		for(int i = 1;i <= n;++i) 
			if(automaton.icnt(i) == ans) 
				printf("%s\n",tmp[i]);
	}
	return;
}
signed main() {
	automation();
}

二次加强

原理似乎是询问时,每个节点不再跳fail指针。

等到了最后一起沿着fail指针跳(拓扑序)。

其实因为我们在建fail指针的时候就是按着拓扑序跑的,所以不必再求一边拓扑序,把之前的队列循环一遍就好了。

单词 也用到了fail指针和拓扑序。

code
#include <stdio.h>
const int N = 2048576;
struct TRIE {
	int sid[26];
	int fail;
	int cnt;
	int flag;
} trie[N];
int trie_tot, top[N], ans[N];
#define edge(id,cid) trie[id].sid[cid]
#define fail(id) trie[id].fail
#define cnt(id) trie[id].cnt
#define flag(id) trie[id].flag
void insert(char *pattern,const int &val) {
	int u = 0;
	for(int i = 0;pattern[i];++i) {
		pattern[i] -= 'a';
		if(!edge(u,pattern[i])) 
			edge(u,pattern[i]) = ++trie_tot;
		u = edge(u,pattern[i]);
	}
	if(!flag(u)) 
		flag(u) = val;
	top[val] = flag(u);
}
int q[N];
int head, tail;
void con() {
	head = tail = 0;
	for(int i = 25;~i;--i) 
		if(q[tail+1] = edge(0,i))
			++tail;
	while(head^tail) {
		int u = q[++head], v;
		for(int i = 25;~i;--i) {
			if(v = edge(u,i)) {
				q[++tail] = v;
				fail(v) = edge(fail(u),i);
			} else 
				edge(u,i) = edge(fail(u),i);
		}
	}
}
void query(const char *text) {
	int u = 0;
	for(int i = 0;text[i];++i) {
		u = edge(u,text[i]-'a');
		++cnt(u);
	}
	for(int i = trie_tot;~i;--i) {
		ans[flag(q[i])] = cnt(q[i]);
		cnt(fail(q[i])) += cnt(q[i]);
	}
}
char tmp[N];
int n;
signed main() {
	scanf("%d",&n);
	for(int i = 1;i <= n;++i) {
		scanf("%s",tmp);
		insert(tmp,i);
	}
	con();
	scanf("%s",tmp);
	query(tmp);
	for(int i = 1;i <= n;++i) 
		printf("%d\n",ans[top[i]]);
}

@bikuhiku

posted @ 2022-06-08 15:27  bikuhiku  阅读(4)  评论(0编辑  收藏  举报