AC自动机模板

来源:互联网 发布:黄金时时彩缩水软件 编辑:程序博客网 时间:2024/04/30 08:21
#include<iostream>#include<cstdio>#include<cstring>#include<queue>using namespace std;struct node{int fail;int next[26];int c;void newnode(){memset(next,-1,sizeof(next));fail=-1,c=0;}}a[2000000];int num;char s[1000005];void insert(){int pos=0,t,i;for(i=0;s[i];++i){t=s[i]-'a';if(a[pos].next[t]==-1){num++;a[num].newnode();a[pos].next[t]=num;}pos=a[pos].next[t];}a[pos].c++;}void KMP() //bfs实现{  queue<int> q;  a[0].fail=-1;  q.push(0);    while(!q.empty())  {     int t=q.front();     q.pop();     for(int i=0;i<26;++i) //寻找子节点{  int x=a[t].next[i];  if(x!=-1) //子节点存在 {if(t==0)a[x].fail=0; //第一层直接指向根节点else{int p=a[t].fail;//父节点失败指针while(p!=-1) {if(a[p].next[i]!=-1) //指针指向的子节点与当前相同{a[x].fail=a[p].next[i];break;}       p=a[p].fail; //往上寻找}if(p==-1)a[x].fail=0; //父节点失败指针不存在,指向根节点 } q.push(x);    }   }    }}int find(){int pos=0,i=0,t,m=0;while(s[i]){t=s[i]-'a';                while(pos!=0 && a[pos].next[t]==-1)pos=a[pos].fail; //沿失败指针往回走                pos=a[pos].next[t];                   if(pos==-1)pos=0; //回到根节点                   int tpos=pos;                while(tpos!=0 && a[tpos].c!=-1) //寻找过某个标记点后标记为-1               {                    m+=a[tpos].c;                    a[tpos].c=-1;                    tpos=a[tpos].fail;                }               ++i;}return m;}int main(){freopen("h.in","r",stdin);freopen("h.out","w",stdout);int T,n;scanf("%d",&T);while(T--){num=0;a[0].newnode();scanf("%d\n",&n);for(int i=1;i<=n;++i){gets(s);insert();}gets(s);KMP();printf("%d\n",find());}return 0;}

失败指针:
对于每个节点,我们可以这样处理:设这个节点上的字母为C,沿着他父亲的失败指针走,直到走到一个节点,他的儿子中也有字母为C的节点。然后把当前节点的失败指针指向那个字目也为C的儿子。如果一直走到了root都没找到,那就把失败指针指向root
原创粉丝点击