AC自动机学习总结
程序员文章站
2024-01-29 13:52:10
...
久闻AC自动机的大名,终于,在准备好KMP和字典树之后,开始学习这个看起来高大上的算法了。
多余的写题的时候在补充吧,学完之后发现他的板子并不难,理解也不算太难,网上有很多种写法,近期研究一下,一些代码的常数的问题。洛谷有道题,直接就是板子:
参考不知名大佬的板子(看了好多人的板子了),然后放弃指针,因为觉得要申请空间,好慢啊。
P3808:https://www.luogu.org/problemnew/show/P3808
AC:
// luogu-judger-enable-o2
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<math.h>
//#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
//#define clean(a,b) memset(a,b,sizeof(a))// 水印
//std::ios::sync_with_stdio(false);
// register
const int MAXN=5e6+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const int mod=998244353;
const double PI=acos(-1.0);
struct node{
int cnt,fail;
int nxt[26];
}trie[MAXN];
int que[MAXN];
char s[MAXN];
int ecnt=0;
void Insert(char *s){//获得字典树
int id=0,len=strlen(s);
for(int i=0;i<len;++i){
int Index=s[i]-'a';
if(trie[id].nxt[Index]==0)
trie[id].nxt[Index]=++ecnt;
id=trie[id].nxt[Index];
}
trie[id].cnt++;
}
void get_fail(){//获得fail回溯
queue<int> que;
while(que.size()) que.pop();
for(int i=0;i<26;++i){
int Index=trie[0].nxt[i];
if(Index){
que.push(Index);
trie[Index].fail=0;
}
}
while(que.size()){
int tmp=que.front();que.pop();
for(int i=0;i<26;++i){
int Index=trie[tmp].nxt[i];
if(Index==0){//这里如果没有后面的字符的话,将它与其他的有效字符连起来
trie[tmp].nxt[i]=trie[trie[tmp].fail].nxt[i];
continue;
}//下面就可以直接连接fail了。
trie[Index].fail=trie[trie[tmp].fail].nxt[i];
que.push(Index);
}
}
}
//void get_fail(){
// int head=0,tail=1;
// for(int i=0;i<26;++i){
// int Index=trie[0].nxt[i];
// if(Index){
// que[tail++]=Index;
// trie[Index].fail=0;
// }
// }
// while(head<tail){
// int tmp=que[head++];
// for(int i=0;i<26;++i){
// int Index=trie[tmp].nxt[i];
// if(Index==0){//失配
// trie[tmp].nxt[i]=trie[trie[tmp].fail].nxt[i];
// continue;
// }
// trie[Index].fail=trie[trie[tmp].fail].nxt[i];
// que[tail++]=Index;
// }
// }
//}
int AC_automation(char *s){//判定
int id=0,ans=0,len=strlen(s);
for(int i=0;i<len;++i){
int Index=trie[id].nxt[s[i]-'a'];
while(Index&&trie[Index].cnt!=-1){
ans+=trie[Index].cnt;
trie[Index].cnt=-1;
Index=trie[Index].fail;
}
id=trie[id].nxt[s[i]-'a'];
}
return ans;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%s",s);
Insert(s);
}
get_fail();
scanf("%s",s);
printf("%d\n",AC_automation(s));
}
/*
4 2
abcd
bce
abd
cd
abcdefg
*/
上一篇: 第二周总结
下一篇: 2019年3月23日字节跳动一面总结