AC自动机

来源:互联网 发布:cs6软件下载 编辑:程序博客网 时间:2024/05/20 18:03

不要问我为什么刚写这个东西。

AC自动机=trie+KMP
【说实话KMP我都不太会写】

(Goes型备注版代码最适合G.S.M.学习了)

AC自动机模板

简单版:(洛谷P3808)
给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。
输入格式:
第一行一个n,表示模式串个数;
下面n行每行一个模式串;
下面一行一个文本串。
输出格式:
一个数表示答案

#include<iostream>#include<cstring>#include<cstdio>#include<queue>using namespace std;#if 0Writers: G.S.M. && Goes#endifstruct ss{    int fail,vis[27],end;    //fail指针 该点的儿子有没有i  以该点做结尾的模串的个数}AC[1000005];int cnt=0;//trie的指针inline void build(string s){    int len=s.length();int now=0;    for(int i=0;i<len;i++){        if(!AC[now].vis[s[i]-'a'])//如果没有这个子节点            AC[now].vis[s[i]-'a']=++cnt;//就把它构造出来        now=AC[now].vis[s[i]-'a'];//向下构造    }AC[now].end+=1;    return ;//一串一串地往里面加}inline void Get_fail(){    queue < int > Q ;    for ( int i = 0 ; i < 26 ; i ++ )    if( AC[0].vis[i] ) {//单独处理 第二层的fail指针        AC[AC[0].vis[i]].fail=0;        Q.push(AC[0].vis[i]);    }    while(!Q.empty()){        int pos=Q.front();Q.pop();        for(int i=0;i<26;i++)//枚举所有字母        if( AC[pos].vis[i] ){//如果存在该子节点            AC[ AC[pos].vis[i] ].fail                = AC[ AC[pos].fail ].vis[i];            Q.push(AC[pos].vis[i]);        }        else AC[pos].vis[i]=AC[AC[pos].fail].vis[i];    }}inline int query(string s){//求解    int len=s.length();int now=0,ans=0;    for(int i=0;i<len;i++){        now=AC[now].vis[s[i]-'a'];        for(int t=now;t&&AC[t].end!=-1;t=AC[t].fail)            ans+=AC[t].end,AC[t].end=-1;    }return ans;}int main(){    int n;string s;cin>>n;    for(int i=1;i<=n;i++){        cin>>s;build(s);    }//构造字典树trie    AC[0].fail=0;Get_fail();    //fail指针(类似KMP的nex指针)    cin>>s;printf("%d\n",query(s));    return 0;}