HDU2222 Keywords Search [AC自动机]

  AC自动机的模版题,应该是很多人的AC自动机处女作吧。。

  在斌牛的讲解下,总算是对AC自动机了解了个大概,这里采用了AC自动机和Trie图两种写法,据说后者在AC自动机DP中用的比较多,应该很快就会做到了。。。两者差不多,Trie图利用失败指针来建图,据说AC自动机到Trie图就是转化成了确定性有穷自动机。

  贴一下两种写法的代码,当模版了。

 AC自动机:

#include <string.h>
#include <stdio.h>
#include <queue>
#define MAXS 500010

int cas,n;
char s[55],find[1000005];
int next[MAXS][26],pos,tot[MAXS],fail[MAXS];
int newnode(){
    memset(next[pos],0,sizeof next[pos]);
    tot[pos]=fail[pos]=0;
    return pos++;
}
void insert(char *s){
    int len=strlen(s);
    int p=0;
    for(int i=0;i<len;i++){
        int k=s[i]-'a';
        p=next[p][k]?next[p][k]:next[p][k]=newnode();
    }
    ++tot[p];
}
void makefail(){
    std::queue<int> q;
    q.push(0);
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=0;i<26;i++){
            int v=next[u][i];
            if(v==0)continue;
            q.push(v);
            if(u==0)continue;
            fail[v]=next[0][i];
            for(int f=fail[u];f!=0;f=fail[f]){
                if(next[f][i]){
                    fail[v]=next[f][i];
                    break;
                }
            }
        }
    }
}
int makeans(char *s){
    int ans=0;
    for(int i=0,p=0;s[i];i++){
        int k=s[i]-'a';
        while(p>0&&!next[p][k])p=fail[p];
        p=next[p][k];
        for(int t=p;t!=0;t=fail[t]){
            if(tot[t]>=0){
                ans+=tot[t];
                tot[t]=-1;
            }else break;
        }
    }
    return ans;
}
int main(){
freopen("test.in","r",stdin);
    scanf("%d",&cas);
    for(int ca=1;ca<=cas;ca++){
        scanf("%d",&n);
        pos=0;newnode();
        for(int i=1;i<=n;i++){
            scanf("%s",s);
            insert(s);
        }
        makefail();
        scanf("%s",find);
        int x=makeans(find);
        printf("%d\n",x);
    }
    return 0;
}

Trie图:

#include <string.h>
#include <stdio.h>
#include <queue>
#define MAXS 500010

int cas,n;
char s[55],find[1000005];
int next[MAXS][26],pos,tot[MAXS],fail[MAXS];
int newnode(){
    memset(next[pos],0,sizeof next[pos]);
    tot[pos]=fail[pos]=0;
    return pos++;
}
void insert(char *s){
    int p=0;
    for(int i=0;s[i];i++){
        int k=s[i]-'a';
        p=next[p][k]?next[p][k]:next[p][k]=newnode();
    }
    ++tot[p];
}
void makefail(){
    std::queue<int> q;
    q.push(0);
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=0;i<26;i++){
            int v=next[u][i];
            if(v==0)next[u][i]=next[fail[u]][i];
            else q.push(v);
            if(v!=0&&u!=0)fail[v]=next[fail[u]][i];
        }
    }
}
int makeans(char *s){
    int ans=0;
    for(int i=0,p=0,j;s[i];i++){
        int k=s[i]-'a';
        p=next[p][k];
        for(int j=p;j&&tot[j]!=-1;j=fail[j]){
            ans+=tot[j];
            tot[j]=-1;
        }
    }
    return ans;
}
int main(){
freopen("test.in","r",stdin);
    scanf("%d",&cas);
    for(int ca=1;ca<=cas;ca++){
        scanf("%d",&n);
        pos=0;newnode();
        for(int i=1;i<=n;i++){
            scanf("%s",s);
            insert(s);
        }
        makefail();
        scanf("%s",find);
        int x=makeans(find);
        printf("%d\n",x);
    }
    return 0;
}

 

 

原文地址:https://www.cnblogs.com/swm8023/p/2623518.html