AC自动机

AC自动机--树上KMP

在博主还没懂其精髓并有足够语言组织能力之前,先挂着,以免把别人带入坑中。

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>

#define ll long long
#define db double
#define inf 0x7fffffff
#define rg register int

using namespace std;

struct su{
    int fail; //匹配失败后跳到哪一个节点
    int son[26]; //儿子的地址
    int end;  //有多少个模式串在这个节点结束
}ac[1000001];

int n,top;
string s;

inline int qr(){ char ch;
    while((ch=getchar())<'0'||ch>'9');
    int res=ch^48;
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+(ch^48);
    return res;
}

inline void build(){
    int l=s.length(),now=0,*son;
    for(rg i=0;i<l;++i){
        son=&ac[now].son[s[i]-'a']; //开个指针方便快捷
        if(!*son)*son=++top; //没有这个字母的位置就新开一个
        now=*son; //把下一位字母放进去
    }++ac[now].end; //这个模式串在这个节点结束
}

inline void failed(){
    queue<int> q; //用BFS来给树上KMP做预处理
    for(rg i=0;i<26;++i)
        if(ac[0].son[i])
            ac[ac[0].son[i]].fail=0,//初始化
            q.push(ac[0].son[i]); //根节点的子节点都指向根节点
    rg i,j,*son,next;
    while(!q.empty()){
        i=q.front(); q.pop();
        for(j=0;j<26;++j){
            son=&ac[i].son[j]; //当前的节点
            next=ac[ac[i].fail].son[j]; //当前节点匹配失败时转向的下一个节点
            if(*son){
                ac[*son].fail=next; //对应68,69行构成(局部)的KMP  #1!
                q.push(*son); //预备下一层
            }else *son=next; //对应第67行,共同构成一个(整体)的KMP #2!
        }
    }
}

inline int find(){
    int l=s.length(),now=0,ans=0;
    for(rg i=0;i<l;++i){
        now=ac[now].son[s[i]-'a']; //匹配下一层,对应59行
        for(rg j=now;j&&ac[j].end>-1;j=ac[j].fail) //原理模仿的KMP算法
            ans+=ac[j].end,ac[j].end=-1; //and改成-1:每个字符串最多匹配一次
    }return ans;
}

int main(){ n=qr();
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    for(rg i=1;i<=n;++i)
        cin>>s,build();//把模式串加入AC自动机
    failed(); cin>>s;
    printf("%d",find());//直接输出
    return 0;
}
posted @ 2019-01-26 19:24  一只不咕鸟  阅读(151)  评论(1编辑  收藏  举报