码题集-AC自动机(模板)

2023-11-30 06:04
文章标签 模板 ac 自动机 码题

本文主要是介绍码题集-AC自动机(模板),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

AC自动机:

(1)一个长串,多个短串,求长串中匹配了几个短串(包括分别匹配了几个,总共匹配了几类)

(2)此处模板为长串中匹配了几个短串;

(3)复杂度为O(n);

(4)理论基础

  1. Trie树
  2. KMP
  3. 链表

思路:

(1)问题分析:给定1e6模式长串,多个短串,求其中匹配的各模式串中个数最大者及其个数;

(2)分析:多模式串匹配问题,考虑AC自动机;

(3)过程:

  1. 建立string数组与int数组统计短串及其个数;
  2. 先建立短串与标记的map映射;
  3. 对于多个子串,建立Trie树,并将短串在Trie树中的终点映射到短串标记;
  4. 建立链式关系;
  5. 查询时查到后对该节点对应短串进行计数;
  6. 找到最大出现次数及其节点;

代码:


#include <queue>
#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#include<map>
using namespace std;
typedef long long ll;
const int maxn =  2*1e6+9;int trie[maxn][26]; //字典树
int cntword[maxn];  //记录该单词出现次数
int fail[maxn];     //失败时的回溯指针
int cnt = 0;
int n;
string s;
map<string,int> qq;
map<int,int> node_i;
int ccnt[50];
string ss[50];void insertWords(string s)
{int root = 0;for(int i=0;i<s.size();i++){int next = s[i] - 'a';if(!trie[root][next])trie[root][next] = ++cnt;root = trie[root][next];}cntword[root]++;      //当前节点单词数+1int s_n = qq[s];node_i[root] = s_n;
}
void getFail(){queue <int>q;for(int i=0;i<26;i++){      //将第二层所有出现了的字母扔进队列if(trie[0][i]){fail[trie[0][i]] = 0;q.push(trie[0][i]);}}//fail[now]    ->当前节点now的失败指针指向的地方
//tire[now][i] -> 下一个字母为i+'a'的节点的下标为tire[now][i]while(!q.empty()){int now = q.front();q.pop();for(int i=0;i<26;i++){      //查询26个字母if(trie[now][i]){//如果有这个子节点为字母i+'a',则
//让这个节点的失败指针指向(((他父亲节点)的失败指针所指向的那个节点)的下一个节点)//有点绕,为了方便理解特意加了括号fail[trie[now][i]] = trie[fail[now]][i];q.push(trie[now][i]);}else//否则就让当前节点的这个子节点//指向当前节点fail指针的这个子节点trie[now][i] = trie[fail[now]][i];}}
}void query(string s)
{int now = 0,ans = 0;for(int i=0;i<s.size();i++){    //遍历文本串now = trie[now][s[i]-'a'];  //从s[i]点开始寻找for(int j=now;j && cntword[j]!=-1;j=fail[j]){//一直向下寻找,直到匹配失败(失败指针指向根或者当前节点已找过).ans += cntword[j];if(cntword[j] > 0){int t = node_i[j];ccnt[t] += 1; }}}
}void solve()
{cnt = 0;memset(trie,0,sizeof trie);memset(cntword,0,sizeof cntword);memset(fail,0,sizeof fail);memset(ccnt,0,sizeof ccnt);node_i.clear();qq.clear();for(int i=0;i<n;i++){cin >> s ;qq[s] = i;ss[i] = s; insertWords(s);}fail[0] = 0;getFail();cin >> s ;query(s);int maxn = 0;for(int i = 0;i < n;i ++){maxn = max(maxn,ccnt[i]);}cout << maxn << endl;for(int i = 0;i < n;i ++){if(ccnt[i] == maxn){cout << ss[i] << endl;}}} int main() 
{while(cin >> n,n != 0){solve();	 	}   return 0;
}

这篇关于码题集-AC自动机(模板)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/435894

相关文章

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

uva 1342 欧拉定理(计算几何模板)

题意: 给几个点,把这几个点用直线连起来,求这些直线把平面分成了几个。 解析: 欧拉定理: 顶点数 + 面数 - 边数= 2。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc

uva 11178 计算集合模板题

题意: 求三角形行三个角三等分点射线交出的内三角形坐标。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <

poj 2104 and hdu 2665 划分树模板入门题

题意: 给一个数组n(1e5)个数,给一个范围(fr, to, k),求这个范围中第k大的数。 解析: 划分树入门。 bing神的模板。 坑爹的地方是把-l 看成了-1........ 一直re。 代码: poj 2104: #include <iostream>#include <cstdio>#include <cstdlib>#include <al

hdu 3065 AC自动机 匹配串编号以及出现次数

题意: 仍旧是天朝语题。 Input 第一行,一个整数N(1<=N<=1000),表示病毒特征码的个数。 接下来N行,每行表示一个病毒特征码,特征码字符串长度在1—50之间,并且只包含“英文大写字符”。任意两个病毒特征码,不会完全相同。 在这之后一行,表示“万恶之源”网站源码,源码字符串长度在2000000之内。字符串中字符都是ASCII码可见字符(不包括回车)。

最大流、 最小费用最大流终极版模板

最大流  const int inf = 1000000000 ;const int maxn = 20000 , maxm = 500000 ;struct Edge{int v , f ,next ;Edge(){}Edge(int _v , int _f , int _next):v(_v) ,f(_f),next(_next){}};int sourse , mee

POJ 1625 自动机

给出包含n个可见字符的字符集,以下所提字符串均由该字符集中的字符构成。给出p个长度不超过10的字符串,求长为m且不包含上述p个字符串的字符串有多少个。 g++提交 int mat[108][108] ;int matn ;int N ;map<char ,int> to ;//ACconst int maxm = 108 ;const int kin

zoj 3228 ac自动机

给出一个字符串和若干个单词,问这些单词在字符串里面出现了多少次。单词前面为0表示这个单词可重叠出现,1为不可重叠出现。 Sample Input ab 2 0 ab 1 ab abababac 2 0 aba 1 aba abcdefghijklmnopqrstuvwxyz 3 0 abc 1 def 1 jmn Sample Output Case 1 1 1 Case 2