zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",ans);
            for(int i=1;i<=n;i++) if(ans==num[i]) printf("%s
    ",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
    ",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
    ",num[id[i]]);
    }
  • 相关阅读:
    西安.NET俱乐部群 推广代码
    跟我学Makefile(六)
    跟我学Makefile(五)
    跟我学Makefile(四)
    跟我学Makefile(三)
    跟我学Makefile(二)
    Kconfig文件说明2
    Kconfig文件说明
    kernel内核配置说明
    makefile中ifeq与ifneq dev/null和dev/zero简介 dd命令
  • 原文地址:https://www.cnblogs.com/waterflower/p/11291421.html
Copyright © 2011-2022 走看看