AC自动机——看似KMP在跑,其实fail在跳

Posted waterflower

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AC自动机——看似KMP在跑,其实fail在跳相关的知识,希望对你有一定的参考价值。

先存代码

 

AC自动机(简单版)

  

#include<bits/stdc++.h>
#define maxn 1000007
using namespace std;
int n,ans;
int tr[maxn][28],val[maxn],cnt,fail[maxn];
char mod[maxn],tx[maxn];
queue<int >q;

void build(char *a)
    int now=0;
    for(int i=0;a[i];i++)
        if(!tr[now][a[i]-a]) tr[now][a[i]-a]=++cnt;
        now=tr[now][a[i]-a];
    
    val[now]++;
//建树 

void AC()
    for(int i=0;i<26;i++) if(tr[0][i]) q.push(tr[0][i]);//26个字母跑 
    while(!q.empty())
        int u=q.front();q.pop();
        for(int i=0;i<26;i++)
            if(tr[u][i]) fail[tr[u][i]]=tr[fail[u]][i],q.push(tr[u][i]);//调取指针 
            else tr[u][i]=tr[fail[u]][i];//建立“虚边”——指向失配指针的i边
            //这里已经改变了trie图 
        
    


int query(char *t)
    int ol=0,u=0;
    for(int i=0;t[i];i++)
        u=tr[u][t[i]-a];
        for(int j=u;j&&val[j]!=-1;j=fail[j])
            ol+=val[j],val[j]=-1;//fail跳(这样其实很慢) 
    
    return ol;


int main()
//    freopen("cin.in","r",stdin);
//    freopen("co.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%s",mod),build(mod);
    AC();
    scanf("%s",tx);ans=query(tx);
    printf("%d\n",ans);

AC自动机(加强版)

#include<bits/stdc++.h>
#define maxn 1000007
using namespace std;
int T,n,ans;
char mod[maxn][100],tx[maxn];

namespace AC
    int tr[maxn][27],fail[maxn],tot;
    int cnt,val[maxn],num[maxn];
    void Init()
        memset(tr,0,sizeof(tr));
        memset(num,0,sizeof(num));
        memset(fail,0,sizeof fail);
        memset(val,0,sizeof val);
        cnt=ans=0;
    
    void insert(char *s,int id)
        int now=0;
        for(int i=0;s[i];i++)
            if(!tr[now][s[i]-a]) tr[now][s[i]-a]=++cnt;
            now=tr[now][s[i]-a];
        
        val[now]=id;//记录id,这个不怕覆盖 
    
    queue<int >q;
    void build()
        for(int i=0;i<26;i++) if(tr[0][i]) q.push(tr[0][i]);
        while(!q.empty())
            int u=q.front();q.pop();
            for(int i=0;i<26;i++)
                if(tr[u][i]) fail[tr[u][i]]=tr[fail[u]][i],q.push(tr[u][i]),cerr<<fail[tr[u][i]]<<endl;
                else tr[u][i]=tr[fail[u]][i];
        
    
    void query(char *t)
        int u=0;
        for(int i=0;t[i];i++)
            u=tr[u][t[i]-a];
            for(int j=u;j;j=fail[j])
                if(val[j]) num[val[j]]++,ans=max(ans,num[val[j]]);
        //还是跳,不过记录的不一样而已 
        printf("%d\n",ans);
        for(int i=1;i<=n;i++) if(ans==num[i]) printf("%s\n",mod[i]);
    


int main()
    scanf("%d",&n);
    while(n)
        AC::Init();
        for(int i=1;i<=n;i++) scanf("%s",mod[i]),AC::insert(mod[i],i);
        AC::build();
        scanf("%s",tx);
        AC::query(tx);
        scanf("%d",&n);
    

AC自动机(二次加强版)

#include<bits/stdc++.h>
#define maxn 2000007
using namespace std;
int n;
char mod[maxn],tx[maxn];
int fail[maxn],tr[maxn][27],val[maxn],num[maxn];
int id[maxn],cnt,in[maxn],to[maxn];

void insert(char *a,int idx)
    int now=0;
    for(int i=0;a[i];i++)
        if(!tr[now][a[i]-a]) tr[now][a[i]-a]=++cnt;
        now=tr[now][a[i]-a];
    
    val[now]++;id[idx]=now;//记录 


queue<int >q;

void build()
    for(int i=0;i<26;i++) if(tr[0][i]) q.push(tr[0][i]);
    while(!q.empty())
        int u=q.front();q.pop();
        for(int i=0;i<26;i++)
            if(tr[u][i]) fail[tr[u][i]]=tr[fail[u]][i],q.push(tr[u][i]),in[fail[tr[u][i]]]++;
            else tr[u][i]=tr[fail[u]][i];
        
    


void query(char *t)
    int u=0;
    for(int i=0;t[i];i++)
        u=tr[u][t[i]-a],num[u]++;


void topu()
    for(int i=1;i<=cnt;i++) if(!in[i]) q.push(i);
    while(!q.empty())
        int u=q.front(),v=fail[u];q.pop();
        num[v]+=num[u];--in[v];
        if(!(in[v])) q.push(v);
    
//这里是跟题解学的topu,效率也挺高 

int main()
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%s",mod),insert(mod,i);
    build();
    scanf("%s",tx);query(tx);
    topu(); 
    for(int i=1;i<=n;i++) printf("%d\n",num[id[i]]);

单词

#include<bits/stdc++.h>
#define maxn 2000007
using namespace std;
int n;
char mod[maxn],tx[maxn],c[maxn];
int fail[maxn],tr[maxn][28],val[maxn],num[maxn];
int id[maxn],cnt,in[maxn],tot;

void insert(char *a,int idx)
    int now=0;
    for(int i=0;a[i];i++)
        if(!tr[now][a[i]-a]) tr[now][a[i]-a]=++cnt;
        now=tr[now][a[i]-a];
    
    val[now]++;id[idx]=now;


queue<int >q;

void build()
    for(int i=0;i<27;i++) if(tr[0][i]) q.push(tr[0][i]);
    while(!q.empty())
        int u=q.front();q.pop();
        for(int i=0;i<27;i++)
            if(tr[u][i]) fail[tr[u][i]]=tr[fail[u]][i],q.push(tr[u][i]),in[fail[tr[u][i]]]++;
            else tr[u][i]=tr[fail[u]][i];
        
    


void query(char *t)
    int u=0;
    for(int i=0;t[i];i++)
        u=tr[u][t[i]-a],num[u]++;


void topu()
    for(int i=1;i<=cnt;i++) if(!in[i]) q.push(i);
    while(!q.empty())
        int u=q.front(),v=fail[u];q.pop();
        num[v]+=num[u];--in[v];
        if(!(in[v])) q.push(v);
    


void work(char *a,char *b)
    int len1=strlen(a),len2=strlen(b);
    for(int i=len1;i<len1+len2;i++)
        a[i]=b[i-len1];


int main()
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%s",c),work(mod,c),
        tot=strlen(mod),insert(c,i),mod[tot++]=;
    build();
    query(mod);topu();
    for(int i=1;i<=n;i++) printf("%d\n",num[id[i]]);

 

以上是关于AC自动机——看似KMP在跑,其实fail在跳的主要内容,如果未能解决你的问题,请参考以下文章

AC自动机(无指针)

ac自动机

AC自动机

AC自动机

AC自动机总结

AC自动机