AC自动机
AC自动机
一直以来,都觉得AC自动机是个特别牛X的算法(因为听着就像是Automaton of accepting answer),事实上此AC并非我们所说的AC,是因为这个算法的英文名字叫Aho-Corasick automaton。但是这个算法确实牛X。今天就来学习了一下,事实上就是KMP的失配指针思想+trie树。
百科上说 AC自动机算法分为3步:1.构造一棵Trie树;2.构造失败指针;3.模式匹配过程。
https://bestsort.cn/ 大佬博客
洛谷P3796 AC自动机加强(kuangbin模板2.0)
#include<iostream> #include<cstring> #include<queue> using namespace std; const int M=1e6+10; struct Trie{ int nxt[M][26],fail[M],end[M],ans[M]; int root,L; int newnode(){ for(int i=0;i<26;i++){ nxt[L][i]=-1; } end[L++]=0; return L-1; } void init(){ memset(end,0,sizeof end); memset(ans,0,sizeof ans); L=0; root=newnode(); } void insert(string buf,int nn){ int len=buf.size(); int now=root; for(int i=0;i<len;i++){ if(nxt[now][buf[i]-'a']==-1) nxt[now][buf[i]-'a']=newnode(); now=nxt[now][buf[i]-'a']; } end[now]=nn; } void build(){ queue<int>Q; fail[root]=root; for(int i=0;i<26;i++){ if(nxt[root][i]==-1) nxt[root][i]=root; else { fail[nxt[root][i]]=root; Q.push(nxt[root][i]); } } while(!Q.empty() ){ int now=Q.front();Q.pop(); for(int i=0;i<26;i++){ if(nxt[now][i]==-1)nxt[now][i]=nxt[fail[now]][i]; else { fail[nxt[now][i]]=nxt[fail[now]][i]; Q.push(nxt[now][i]); } } } } void query(string buf){ int len=buf.size(); int now=root; int res=0; for(int i=0;i<len;i++){ now=nxt[now][buf[i]-'a']; for(int t=now;t;t=fail[t])ans[end[t]]++; } } }ac; string buf; string str[M]; int main(){ int n; while(cin>>n){ if(!n)break; ac.init(); for(int i=1;i<=n;i++){ cin>>str[i]; ac.insert(str[i],i); } ac.build(); cin>>buf; ac.query(buf); int mx=0; //for(int i=0;i<=n;i++)cout<<ac.ans[i]<<"*********"<<endl; for(int i=1;i<=n;i++)mx=max(mx,ac.ans[i]); cout<<mx<<endl; for(int i=1;i<=n;i++){ if(ac.ans[i]==mx)cout<<str[i]<<endl; } } return 0; }
n个(病毒)字符串建字典树,m篇文章,query m次 每次维护一个ans[ ] 记录第几个病毒出现过,ans[0]为总数
代码
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; #define r(a) scanf("%d",&a) const int M=1e5+5; char s[M]; int n,m,ans[M],cnt; struct AHO { int ch[M][130],sz,fail[M],end[M],cnt; bool vis[M]; void init() { sz=0; ans[0]=0; for(int i=0; i<=M; i++)vis[i]=0; } void insert(int id) { int len=strlen(s),now=0; for(int i=0; i<len; i++) { int x=s[i]; if(!ch[now][x])ch[now][x]=++sz; now=ch[now][x]; } end[now]=id; } queue<int>q; void get_fail() { while(!q.empty())q.pop(); for(int i=0; i<=128; i++)if(ch[0][i])q.push(ch[0][i]); while(!q.empty()) { int now=q.front(); q.pop(); for(int i=0; i<=128; i++) { if(!ch[now][i]) { ch[now][i]=ch[fail[now]][i]; continue; } fail[ch[now][i]]=ch[fail[now]][i]; q.push(ch[now][i]); } } } void query() { ans[0]=0; for(int i=0; i<=M; i++)vis[i]=0; int len=strlen(s),now=0; for(int i=0; i<len; i++) { vis[now]=1; int x=s[i]; int y=ch[now][x]; while(y&&!vis[y]) { vis[y]=1; // if(end[y])ans[++ans[0]]=end[y]; // /* ans+=(end[y]!=0); */ y=fail[y]; } now=ch[now][x]; } } } ac; int main() { scanf("%d\n",&n); for(int i=1; i<=n; i++) { gets(s); ac.insert(i); } scanf("%d\n",&m); ac.get_fail(); for(int j=1; j<=m; j++) { gets(s); ac.qurry(); if(ans[0]) { printf("web %d: ",j); sort(ans+1,ans+ans[0]+1); for (int i=1; i<=ans[0]; ++i) printf("%d%c",ans[i]," \n"[i==ans[0]]); ++cnt; } } printf("total: %d\n",cnt); return 0; }
AC自动机标准模板
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; #define r(a) scanf("%d",&a) const int M=1e5+5; char s[M]; struct AHO { int ch[M][30],sz,fail[M],is_end[M],ans; bool vis[M]; void init() { sz=0; ans=0; for(int i=0; i<=M; i++)vis[i]=0; } void insert() { int len=strlen(s),now=0; for(int i=0; i<len; i++) { int x=s[i]-'a'; if(!ch[now][x])ch[now][x]=++sz; now=ch[now][x]; } is_end[now]++; } queue<int>q; void get_fail() { while(!q.empty())q.pop(); for(int i=0; i<=26; i++)if(ch[0][i])q.push(ch[0][i]); while(!q.empty()) { int now=q.front(); q.pop(); for(int i=0; i<=26; i++) { if(!ch[now][i]) { ch[now][i]=ch[fail[now]][i]; continue; } fail[ch[now][i]]=ch[fail[now]][i]; q.push(ch[now][i]); } } } int query() { ans=0; for(int i=0; i<=M; i++)vis[i]=0; int len=strlen(s),now=0; for(int i=0; i<len; i++) { vis[now]=1; int x=s[i]-'a'; int y=ch[now][x]; while(y&&!vis[y]) { vis[y]=1; ans+=is_end[y]; y=fail[y]; } now=ch[now][x]; } return ans; } } ac; int main() { int T,n; r(T); while(T--){ ac.init(); scanf("%d\n",&n); for(int i=1;i<=n;i++){ gets(s); ac.insert(); } gets(s); ac.get_fail(); cout<<ac.query()<<endl; } return 0; }
AC自动机
n个模式串 问n个串再主串中出现了多少次,(AA 在 AAA中出现了两次)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; #define r(a) scanf("%d",&a) const int M=5e4+100; const int N=1e3+10; const int sig_M=128; int cnt[N]; struct AHO { int ch[M][sig_M],f[M],sz,fail[M],end[M]; void init() { sz=0; memset(ch[0],0,sizeof(ch[0])); end[0]=f[0]=fail[0]=0; } void insert(char *s,int id) { int len=strlen(s),now=0; for(int i=0; i<len; i++) { int x=s[i]; if(!ch[now][x]) { ch[now][x]=++sz; memset(ch[sz],0,sizeof(ch[sz])); end[sz]=0; } now=ch[now][x]; } end[now]=id; } void dfs(int k) { if(end[k]) { cnt[end[k]]++; dfs(fail[k]); } } void query(char *s) { int len=strlen(s),now=0; for(int i=0; i<len; i++) { int x=s[i]; while(now&&ch[now][x]==0) { now=f[now]; } now=ch[now][x]; if(end[now])dfs(now); else if(fail[now])dfs(fail[now]); } } void get_fail() { queue<int>q; f[0]=0; for(int i=0; i<sig_M; i++) { int u=ch[0][i]; if(u) { fail[u]=f[u]=0; q.push(u); } } while(!q.empty()) { int now=q.front(); q.pop(); for(int i=0; i<sig_M; i++) { int u=ch[now][i]; if(!u) continue; q.push(u); int v=f[now]; while(v&&ch[v][i]==0)v=f[v]; f[u]=ch[v][i]; fail[u]= end[f[u]]?f[u]:fail[f[u]]; } } } } ac; char w[N][60]; char t[2000000+100]; int main() { int n; while(scanf("%d",&n)==1&&n) { ac.init(); memset(cnt,0,sizeof(cnt)); for(int i=1; i<=n; i++) { scanf("%s",w[i]); ac.insert(w[i],i); } ac.get_fail(); scanf("%s",t); ac.query(t); for(int i=1; i<=n; i++) { if(cnt[i]) cout<<w[i]<<": "<<cnt[i]<<endl; } } return 0; }

浙公网安备 33010602011771号