AC自动机
AC自动机
简介
AC自动机是的代码基本步骤:
- 第一步,建一颗字典树来存储
数组 - 第二步,构建失配指针。找到两个子节点,按照它们的父亲向上找。一直找到祖先一样,就可以返回了。
- 第三步匹配。首先,我们用一个指针指向根节点,接着,读入单词,检查是否存在这个子节点,然后指针跳转到子结点,如果不存在,就直接跳到失配指针即可。
代码
P3808 【模板】AC 自动机(简单版)
这体就是一道AC自动机的模板题。
第一步:建树,用字典树来储存这个结构
void insert(string& s){//建树
int u=0;
for(int i=0; s[i]; i++){
int v=s[i]-'a';
if(!trie[u].son[v]){//还没有被建过
//if(trie[u].son[v]==0) 说明这个节点还没有被建造过,需要用一个新的数字作为下标tot+1来储存
trie[u].son[v]=++tot;//为这个不同的子节点来建立新的节点
}
u=trie[u].son[v];
}
trie[u].cnt++;
}
第二步:构建失配指针
void getfail(){
queue<int> q;
for(int v=0; v<26; v++){
int c=trie[0].son[v];
if(c){
trie[c].fail=0;
q.push(c);
}
}
while(!q.empty()){
int u=q.front();
q.pop();
int f=trie[u].fail;
for(int v=0; v<26; v++){
int c=trie[u].son[v];
if(c){
trie[c].fail=trie[f].son[v];
q.push(c);
}
else{
trie[u].son[v]=trie[f].son[v];
}
}
}
}
第三步:匹配
int find(string& s){
int u=0;
int sum=0;
for(int i=0; s[i]; i++){
int v=s[i]-'a';
int c=trie[u].son[v];
while(c && trie[c].cnt!=-1){
//while(c!=0 && trie[c].cnt!=-1)
sum+=trie[c].cnt;
trie[c].cnt=-1;
c=trie[c].fail;
}
u=trie[u].son[v];
}
return sum;
}
完整代码
#include<queue>
#include<vector>
#include<iostream>
#define endl "\n"
//0 false
using namespace std;
struct mktr{
int son[30];//儿子只有可能是A到Z26个字符,所以数组只需要开到30就肯定够
int cnt,fail;
}trie[500010];
int tot=0;
void insert(string& s){//建树
int u=0;
for(int i=0; s[i]; i++){
int v=s[i]-'a';
if(!trie[u].son[v]){//还没有被建过
//if(trie[u].son[v]==0) 说明这个节点还没有被建造过,需要用一个新的数字作为下标tot+1来储存
trie[u].son[v]=++tot;//为这个不同的子节点来建立新的节点
}
u=trie[u].son[v];
}
trie[u].cnt++;
}
void getfail(){
queue<int> q;
for(int v=0; v<26; v++){
int c=trie[0].son[v];
if(c){
trie[c].fail=0;
q.push(c);
}
}
while(!q.empty()){
int u=q.front();
q.pop();
int f=trie[u].fail;
for(int v=0; v<26; v++){
int c=trie[u].son[v];
if(c){
trie[c].fail=trie[f].son[v];
q.push(c);
}
else{
trie[u].son[v]=trie[f].son[v];
}
}
}
}
int find(string& s){
int u=0;
int sum=0;
for(int i=0; s[i]; i++){
int v=s[i]-'a';
int c=trie[u].son[v];
while(c && trie[c].cnt!=-1){
//while(c!=0 && trie[c].cnt!=-1)
sum+=trie[c].cnt;
trie[c].cnt=-1;
c=trie[c].fail;
}
u=trie[u].son[v];
}
return sum;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
//cout.tie(0);
int n;
string s;
cin>>n;
for(int i=0; i<n; i++){
cin>>s;
insert(s);//建树
}
getfail();
cin>>s;
cout<<find(s)<<endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】