AC自动机 P3808 P3796

第一次写AC自动机##

简单版的这道题可以在进行匹配的时候剪一下枝,应为之前比配过了,不用在匹配了。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <queue>
using namespace std;
const int MAXN=1e6+10;
queue<int> que;

struct AC{
    int tr[MAXN][26],fail[MAXN],val[MAXN],tot;

    void insert(char *s){
        int n=strlen(s+1),p=0;
        for(int i=1;i<=n;i++){
            if(!tr[p][s[i]-'a'])
                tr[p][s[i]-'a']=++tot;
            p=tr[p][s[i]-'a'];
        }
        val[p]++;
    }

    void getfail(){
        while(!que.empty()) que.pop();
        for(int i=0;i<26;i++)
            if(tr[0][i])
                que.push(tr[0][i]);
        while(!que.empty()){
            int u=que.front();que.pop();
            for(int i=0;i<26;i++)
                if(tr[u][i]) fail[tr[u][i]]=tr[fail[u]][i],que.push(tr[u][i]);
                else tr[u][i]=tr[fail[u]][i];
        }
        // for(int i=0;i<=tot;i++) cout<<fail[i]<<" ";cout<<endl;
        // for(int i=0;i<=tot;i++) cout<<val[i]<<" ";cout<<endl;
    }

    int ask(char *s){
        int n=strlen(s+1),p=0,ans=0;
        for(int i=1;i<=n;i++){
            p=tr[p][s[i]-'a'];
            for(int t=p;t&&val[t]!=-1;t=fail[t])
                ans+=val[t],val[t]=-1;
        }
        return ans;
    }
}ac;

int n;
char s[MAXN];

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        ac.insert(s);
    }
    ac.getfail();
    scanf("%s",s+1);
    int ans=ac.ask(s);
    printf("%d
",ans);
    return 0;
}

加强版的题,就不能剪枝了,因为要求出每个模式串出现的次数。

可以在 (trie) 的末节点上记录该串的 (id) 然后每次匹配到就给它++就行了。

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
const int MAXN=1e6+10;
queue<int> que;
int cnt[160],ans,n;
char s[160][100],str[MAXN];

struct AC{
    int tr[16000][26],fail[MAXN],val[MAXN],tot;

    void init(){
        memset(cnt,0,sizeof(cnt));
        memset(tr,0,sizeof(tr));
        memset(fail,0,sizeof(fail));
        memset(val,0,sizeof(val));
        tot=0;
        ans=0;
    }

    void insert(char *s,int id){
        int n=strlen(s+1),p=0;
        for(int i=1;i<=n;i++){
            if(!tr[p][s[i]-'a']) tr[p][s[i]-'a']=++tot;
            p=tr[p][s[i]-'a'];
        }
        val[p]=id;
    }

    void getfail(){
        while(!que.empty()) que.pop();
        for(int i=0;i<26;i++)
            if(tr[0][i]) que.push(tr[0][i]);
        while(!que.empty()){
            int u=que.front();que.pop();
            for(int i=0;i<26;i++)
                if(tr[u][i]) fail[tr[u][i]]=tr[fail[u]][i],que.push(tr[u][i]);
                else tr[u][i]=tr[fail[u]][i];
        }
    }

    void ask(char *s){
        int n=strlen(s+1),p=0;
        for(int i=1;i<=n;i++){
            p=tr[p][s[i]-'a'];
            for(int t=p;t;t=fail[t])
                if(val[t]) cnt[val[t]]++,ans=max(ans,cnt[val[t]]);
        }
    }
}ac;

int main(){
    while(~scanf("%d",&n)){
        if(!n) break;
        ac.init();
        for(int i=1;i<=n;i++) 
            scanf("%s",s[i]+1),
            ac.insert(s[i],i);
        ac.getfail();
        scanf("%s",str+1);
        ac.ask(str);
        printf("%d
",ans);
        for(int i=1;i<=n;i++) if(cnt[i]==ans) printf("%s
",s[i]+1);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/BakaCirno/p/11771700.html