Keywords Search AC自动机QAQ

2024-03-02 08:32
文章标签 search ac qaq 自动机 keywords

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

AC自动机,一直以来都以为是一个非常高大上的算法,其实它还真的挺高大上的。

首先来说,ac自动机的思想与kmp类似,需要自己模拟来理解。

给两个博客:

http://www.cppblog.com/menjitianya/archive/2014/07/10/207604.html

https://blog.csdn.net/KXL5180/article/details/88093307

还有bibi上有个挺好的视频可以看一下,有助于理解

板子分为3个部分来:

首先对于需要的数组

int cnt,root;//cnt表示树的某个节点位置;root表示根,其实就是0;
int fail[maxn];//表示上一个他这个字符的位置。
int ch[maxn][30];//用来表示一个新的节点,存的值是下一个字符的位置
int val[maxn];//表示某个节点的有效值,就是以该点串串结尾的个数

1.建树。建立字典树,这里开了静态的空间来装线段树。

int cnt,root; //N=26;
void init(){cnt=0;root=newnode();}int newnode()//建立新的一个节点,并初始化fail指针与val值为0;{for(int i=0;i<N;i++)ch[cnt][i]=0;val[cnt]=fail[cnt++]=0;return cnt-1;}
void insert(char *s)//插入某一个字符串{int len=strlen(s);int u=0;for(int i=0;i<len;i++){int v=s[i]-'a';if(!ch[u][v])//如果有该点就不开新节点ch[u][v]=newnode();//没有就开新节点u=ch[u][v];}val[u]++;//每当加完一个新的字符串,结尾其实就是节点要val值加1,表示这点是某个串串的结束}

2.建立fail指针。

fail指针的意义就是如果找一个点的时候,你可以找他的fail指针找到有相同作用的点,当某个点寻找下一点失败的时候有fail指针引导你下次应该跳转的位置。自己并不能说的很清楚。

可以参考博客:https://blog.csdn.net/u013371163/article/details/60469145

void getfail(){queue<int >q;int u=0;for(int i=0;i<N;i++)//找到连接root节点的点,加入队列fail指针已经是0了不用重新赋值。if(ch[u][i])q.push(ch[u][i]);while(!q.empty())//类似于bfs的搜索方式{u=q.front();q.pop();for(int i=0;i<N;i++){if(ch[u][i])//如果u节点有下对应的(i+‘a’){fail[ch[u][i]]=ch[fail[u]][i];//这个点fail指针就是连接到他父亲的fail指针对应位置下的那个'a'+i字母的位置。//因为假设u点的fail的位置为v,那么v这个点的作用其实同u点,那么ch[v][i]即v下边如果有那个'a'+i字母,那么这个位置之前已经知道了,赋过去就行//如果没有呢,那么其实之前开辟新节点也是处理过的,fail[cnt][i]=0,那么他的fail指针就是指向0,就是根节点。q.push(ch[u][i]);}elsech[u][i]=ch[fail[u]][i];//如果u没有'a'+i这个字母,就把它的位置(注意是位置)直接跳到上边解释的位置,查询的时候模拟一下就知道了}}}

3.查找某个串的匹配串有几种。

int query(char *s)//查询的时候是需要自己模拟一下{int len=strlen(s);int u=0,ans=0;for(int i=0;i<len;i++){int v=s[i]-'a';u=ch[u][v];//找到u下边的'a'+i字母的位置for(int j=u;j&&~val[j];j=fail[j])//fail指针走到根节点,或者某个点走过了{ans+=val[j];//加上某个节点的值,其实就是加上串尾点val[j]=-1;//标记为走过}}return ans;}

AC代码

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<set>
#include<stack>
#include<vector>
#include<map>
#include<queue>
#define myself i,l,r
#define lson i<<1
#define rson i<<1|1
#define Lson i<<1,l,mid
#define Rson i<<1|1,mid+1,r
#define half (l+r)/2
#define inff 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define me(a,b) memset(a,b,sizeof(a))
#define min4(a,b,c,d) min(min(a,b),min(c,d))
#define min3(x,y,z) min(min(x,y),min(y,z))
#define max4(a,b,c,d) max(max(a,b),max(c,d))
#define max3(x,y,z) max(max(x,y),max(y,z))
typedef long long ll;
using namespace std;
const int maxn=5e5+5;
const int maxm=1e6+5;
const int N=26;
struct AC
{int cnt,root;int fail[maxn];int ch[maxn][30];int val[maxn];int newnode(){for(int i=0;i<N;i++)ch[cnt][i]=0;val[cnt]=fail[cnt++]=0;return cnt-1;}void init(){cnt=0;root=newnode();}void insert(char *s){int len=strlen(s);int u=0;for(int i=0;i<len;i++){int v=s[i]-'a';if(!ch[u][v])ch[u][v]=newnode();u=ch[u][v];}val[u]++;}void getfail(){queue<int >q;int u=0;for(int i=0;i<N;i++)//找到连接root节点的点,加入队列fail指针已经是0了不用重新赋值。if(ch[u][i])q.push(ch[u][i]);while(!q.empty())//类似于bfs的搜索方式{u=q.front();q.pop();for(int i=0;i<N;i++){if(ch[u][i])//如果u节点有下对应的(i+‘a’){fail[ch[u][i]]=ch[fail[u]][i];//这个点fail指针就是连接到他父亲的fail指针对应位置下的那个'a'+i字母的位置。//因为假设u点的fail的位置为v,那么v这个点的作用其实同u点,那么ch[v][i]即v下边如果有那个'a'+i字母,那么这个位置之前已经知道了,赋过去就行//如果没有呢,那么其实之前开辟新节点也是处理过的,fail[cnt][i]=0,那么他的fail指针就是指向0,就是根节点。q.push(ch[u][i]);}elsech[u][i]=ch[fail[u]][i];//如果u没有'a'+i这个字母,就把它的位置(注意是位置)直接跳到上边解释的位置,查询的时候模拟一下就知道了}}}int query(char *s)//查询的时候是需要自己模拟一下{int len=strlen(s);int u=0,ans=0;for(int i=0;i<len;i++){int v=s[i]-'a';u=ch[u][v];//找到u下边的'a'+i字母的位置for(int j=u;j&&~val[j];j=fail[j])//fail指针走到根节点,或者某个点走过了{ans+=val[j];//加上某个节点的值,其实就是加上串尾点val[j]=-1;//标记为走过}}return ans;}
}AC;
char str[maxm];
int main()
{int t,n;cin>>t;while(t--){scanf("%d",&n);AC.init();while(n--){scanf("%s",str);AC.insert(str);}AC.getfail();scanf("%s",str);printf("%d\n",AC.query(str));}return 0;
}

 

这篇关于Keywords Search AC自动机QAQ的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

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

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

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

AI基础 L9 Local Search II 局部搜索

Local Beam search 对于当前的所有k个状态,生成它们的所有可能后继状态。 检查生成的后继状态中是否有任何状态是解决方案。 如果所有后继状态都不是解决方案,则从所有后继状态中选择k个最佳状态。 当达到预设的迭代次数或满足某个终止条件时,算法停止。 — Choose k successors randomly, biased towards good ones — Close

D4代码AC集

贪心问题解决的步骤: (局部贪心能导致全局贪心)    1.确定贪心策略    2.验证贪心策略是否正确 排队接水 #include<bits/stdc++.h>using namespace std;int main(){int w,n,a[32000];cin>>w>>n;for(int i=1;i<=n;i++){cin>>a[i];}sort(a+1,a+n+1);int i=1

JavaScript正则表达式六大利器:`test`、`exec`、`match`、`matchAll`、`search`与`replace`详解及对比

在JavaScript中,正则表达式(Regular Expression)是一种用于文本搜索、替换、匹配和验证的强大工具。本文将深入解析与正则表达式相关的几个主要执行方法:test、exec、match、matchAll、search和replace,并对它们进行对比,帮助开发者更好地理解这些方法的使用场景和差异。 正则表达式基础 在深入解析方法之前,先简要回顾一下正则表达式的基础知识。正则

插件maven-search:Maven导入依赖时,使用插件maven-search拷贝需要的依赖的GAV

然后粘贴: <dependency>    <groupId>mysql</groupId>    <artifactId>mysql-connector-java</artifactId>    <version>8.0.26</version> </dependency>

正规式与有限自动机例题

答案:D 知识点: 正规式 正规集 举例 ab 字符串ab构成的集合 {ab} a|b 字符串a,b构成的集合 {a,b} a^* 由0或者多个a构成的字符串集合 {空,a,aa,aaa,aaaa····} (a|b)^* 所有字符a和b构成的串的集合 {空,a,b,ab,aab,aba,aaab····} a(a|b)^* 以a为首字符的a,b字符串的集

HDU 3037 今年暑假不AC

题目: http://acm.hdu.edu.cn/showproblem.php?pid=2037 题解: 对结束时间排序,然后进行一次遍历,寻找开始时间不小于上一个结束时间的节目。 代码: #include<stdio.h>#include<iostream>using namespace std;struct program{int start,end;}p[101

广度优先搜索Breadth-First-Search

目录  1.问题 2.算法 3.代码 4.参考文献  1.问题         广度优先搜索,稍微学过算法的人都知道,网上也一大堆资料,这里就不做过多介绍了。直接看问题,还是从下图招到一条从城市Arad到Bucharest的路径。  该图是连通图,所以必然存在一条路径,只是如何找到最短路径。 2.算法 还是贴一个算法的伪代码吧: 1 procedu