HDU2222 Keywords Search [AC自动机]

本文详细解读了AC自动机及其与Trie图的关系,并提供了两种实现方式的代码模版,帮助读者理解这两种数据结构在解决字符串匹配问题时的应用。

  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/archive/2012/08/05/2623518.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值