AC自动机

来源:互联网 发布:gps模拟软件 编辑:程序博客网 时间:2024/05/29 07:13

给定多个模式串,一个目标串,查询模式串在目标串中出现的次数。
暴力,KMP都会超时,于是我们要用一个新的方法,在Trie树上做KMP。
具体的插入和Trie树一致,而多了一个fail数组,其含义和KMP中的失配函数一致。
我们可以通过bfs实现处理每一个点的fail,之后再进行匹配即可。
在树上把路径之和全部相加,所得答案即为出现次数。

#include<cstdio>#include<cstring>#include<queue>using namespace std;const int kind=26;struct node{    node *fail;    node *nex[kind];    int cnt;    node(){        fail=NULL;        cnt=0;        memset(nex,NULL,sizeof(nex));    }};inline int idx(char c){return c-'a';}queue<node*> q1;char s[1000005],b[100005];int n;void Insert(char *s,node *root){    int ls=strlen(s);    node *p=root;    for(int i=0;i<ls;++i){        if(p->nex[idx(s[i])]==NULL)        p->nex[idx(s[i])]=new node();        p=p->nex[idx(s[i])];    }    p->cnt++;}void build(node *root){    root->fail=NULL;    q1.push(root);    while(!q1.empty()){      node *tmp=q1.front(),*p=NULL; q1.pop();      for(int i=0;i<26;++i)      if(tmp->nex[i]!=NULL){        if(tmp==root) tmp->nex[i]->fail=root;        else{          p=tmp->fail;          while(p!=NULL){            if(p->nex[i]!=NULL){              tmp->nex[i]->fail=p->nex[i];              break;            }            p=p->fail;          }          if(p==NULL) tmp->nex[i]->fail=root;        }        q1.push(tmp->nex[i]);      }    }}int query(node *root){    int cnt=0,ls=strlen(s);    node *p=root;    for(int i=0;i<ls;++i){      while(p->nex[idx(s[i])]==NULL&&p!=root) p=p->fail;      p=p->nex[idx(s[i])];      if(p==NULL) p=root;      node *tmp=p;      while(tmp!=root && tmp->cnt!=-1){        cnt+=tmp->cnt;        tmp->cnt=-1;        tmp=tmp->fail;      }    }    return cnt;}int main(){    scanf("%s%d",s,&n);    node *root=new node();    for(int i=1;i<=n;++i){        scanf("%s",b);        Insert(b,root);    }    build(root);    printf("%d",query(root));    return 0;}
原创粉丝点击