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;
}

 

AC自动机

病毒入侵 :

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;
}

 

 

 

posted @ 2019-08-13 16:22  GeraldG  阅读(138)  评论(0)    收藏  举报