ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AC自动机 (Trie 板子)

2021-05-26 23:02:17  阅读:248  来源: 互联网

标签:AC Trie flag ++ son int trie fail 自动机


大自然的帮运工

使用板子注意事项:

注意:
1.串是否全是小写字母
2.根节点为1
3.节点数不超过maxn
4.多组数据注意 清空
5.复杂度嘛。。。。。建树o(n*len)

前置知识:Trie树

在这里插入图片描述

需求:
给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。
输入n个模式串, 一个原串
输出结果: 原串中含有模式串的个数。

in:
6
abcd
cd
cd
cdac
aab 
abcdac
out:
5
#include<bits/stdc++.h>
#define maxn 1000001
using namespace std;
struct kkk{
	int son[26];  //一般是小写字母 所以26个 
	int flag; ///相同模式串出现次数 或者是标记 
    int fail;  /// 失配指针
    
}trie[maxn];   // maxn 树节点数 
int n, cnt;   // n个模式串  初始根编号 1 
string s;     // 子串 
//建字典树 
void insert(string s){
	int u = 1;
	int len = s.length();
	for (int i = 0; i < len;i++){
		int v = s[i] - 'a';
		if(!trie[u].son[v]){
			trie[u].son[v] = ++cnt;
		}
		u = trie[u].son[v];
	}
	trie[u].flag++;
}
// 设置失配指针   
// fail  当前字符串最长的后缀字符串 在Trie上的可以找到的编号 
void getFail(){
	
	for (int i = 0; i < 26;i++){
		trie[0].son[i] = 1;   
	}
	queue<int> q;
	q.push(1);
	// 失配 
	trie[1].fail = 0;
	while(!q.empty()){
		int fa = q.front();
		//cout<<fa<<endl;
		q.pop();
		int fafail = trie[fa].fail;
		for (int i = 0; i < 26;i++){
			int v = trie[fa].son[i];
			// 下面trie[v].fail = trie[fafail].son[i];
			// 有点dp的味道  
            if(!v){
            	//fa没有该v节点 所以用他的最长后缀字符串
				// 的儿子节点来代替他。 
				trie[fa].son[i] = trie[fafail].son[i];
				continue;
			}
			
			trie[v].fail = trie[fafail].son[i];
			q.push(v);
		}
	}
}
// 原串与模式串的 关系 
int query(string s){
	int u = 1, ans = 0;
	int len = s.length();
	// 这个循环也很好理解
	// 其实就是两个位置 i是串的右边,现在找该串的左边的位置j
	//  要求j到i是该模式串,那要怎么做呢,用前面的trie树和失配指针
	// 当然对于每个i有很多个j嘛, 模式串又不止一个是吧
	//  
	for (int i = 0; i < len;i++){
		int v = s[i] - 'a';
		int k = trie[u].son[v];
		 // while 模式串不止一个 所以有种关系是可以找出j
		 //  关系即是 k=trie[u].fail;  不断迭代 直至没得了 
		while(k>1 and trie[k].flag!=-1){
			ans += trie[k].flag;
			trie[k].flag = -1;
			k = trie[k].fail;
		}
		u = trie[u].son[v];
	}
	return ans;
}
int main(){
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
	cnt = 1; 
	// Trie树  根节点是 1 ,什么都没有
	// 类型头指针 
	cin >> n;
	for (int i = 1; i <= n;i++){
		cin >> s;
		insert(s);
	}
	getFail();
	cin >> s;
	cout << query(s);
	return 0;
}

TWO (板子)

in:
2
aba
bab
ababababac
6
beta
alpha
haha
delta
dede
tata
dedeltalphahahahototatalpha
0
out:
4
aba
2
alpha
haha

需求:
1、求出现次数最多的次数
2、求出现次数最多的模式串
传送门
多组输入: 当n==0时退出。 注意每次用时clear清空

AC代码:

#include<bits/stdc++.h>
#define maxn 1000001
using namespace std;
struct kkk{
	int son[26];
	int flag; ///相同模式串出现次数 
    int fail;  /// 失配指针
    void clear(){
		memset(son, 0, sizeof(son));
		fail = flag = 0;
	}
}trie[maxn];
int n, cnt,ans;
string s;
string a[200];
int vis[200];
void insert(string s,int num){
	int u = 1;
	int len = s.length();
	for (int i = 0; i < len;i++){
		int v = s[i] - 'a';
		if(!trie[u].son[v]){
			trie[u].son[v] = ++cnt;
		}
		u = trie[u].son[v];
	}
	// 存位置 
	trie[u].flag=num;
}
void getFail(){
	for (int i = 0; i < 26;i++){
		trie[0].son[i] = 1;
	}
	queue<int> q;
	q.push(1);
	trie[1].fail = 0;
	while(!q.empty()){
		int fa = q.front();
		//cout<<fa<<endl;
		q.pop();
		int fafail = trie[fa].fail;
		for (int i = 0; i < 26;i++){
			int v = trie[fa].son[i];
            if(!v){
				trie[fa].son[i] = trie[fafail].son[i];
				continue;
			}
			trie[v].fail = trie[fafail].son[i];
			q.push(v);
		}
	}
}
int query(string s){
	int u = 1, ans = 0;
	int len = s.length();
	for (int i = 0; i < len;i++){
		int v = s[i] - 'a';
		int k = trie[u].son[v];
		while(k>1){
			// 找到了模式串就对该串的vis++ 
			if(trie[k].flag){
				vis[trie[k].flag]++;
			}
			k = trie[k].fail;
		}
		u = trie[u].son[v];
	}
	return ans;
}
void clear(){
	for (int i = 0; i <= cnt;i++){
		trie[i].clear();
	}
	for (int i = 1; i <= n;i++){
		vis[i] = 0;
	}
		cnt = 1;
	ans = 0;
}
void solve(){
	cnt = 1;
    while(1){
		scanf("%d",&n);
		if(n==0)
			break;
		clear();
		for (int i = 1; i <= n;i++)
		{
			cin >> a[i];
			insert(a[i], i);
		}
		getFail();
		cin >> s;
		query(s);
		for (int i = 1; i <= n;i++){
			ans = max(vis[i], ans);
		}
		cout << ans<<endl;
		for (int i = 1; i <= n;i++){
               if(vis[i]==ans){
				   cout << a[i] << endl;
			   }
		}
	}
	return  ;
}
int main(){
	freopen("in.txt", "r", stdin);
  	freopen("out.txt","w", stdout);
	solve();
	return 0;
}

标签:AC,Trie,flag,++,son,int,trie,fail,自动机
来源: https://blog.csdn.net/weixin_45819197/article/details/117307098

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有