AC自动机

来源:互联网 发布:网络维护常见问题 编辑:程序博客网 时间:2024/06/05 14:09

http://www.cnblogs.com/Booble/archive/2010/12/05/1897121.html

//hdu2222//ACauto//构造失败指针:设当前节点上的字母为C,沿着他父亲的失败指针走,直到走到一个节点,他的儿子中也有字母为C的。然后把当前节点的失败指针指向那个字母也为C的儿子。如果一直走到了root都没找到,那就把失败指针指向root。//匹配(1)当前字符匹配,只需沿该路径走向下一个节点继续匹配即可;(2)当前字符不匹配,则去当前节点失败指针所指向的字符继续匹配.重复这2个过程中的一个,直到模式串走完。#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<queue>#define cha 26#define Root 0#define N 500001using namespace std;struct node{    int data;//结点信息    int count;//从根到此处是否是关键字,并且记录是多少个关键字的结尾    int fail;    int next[cha];}tree[N];void init(node &a,int data){    a.data = data;    a.count = 0;    a.fail = Root;    for(int i=0;i<cha;i++)        a.next[i] = -1;}int k = 1;void Insert(char s[]){    int p = Root;    for(int i=0;s[i];i++){        int data = s[i]-'a';        if(tree[p].next[data]==-1){//不存在该结点            init(tree[k],data);            tree[p].next[data] = k;            k++;        }        p = tree[p].next[data];    }    tree[p].count++;}queue<node> q;void AC_automation(){    q.push(tree[Root]);    while(!q.empty()){        node k = q.front();        q.pop();        for(int j=0; j<cha; j++){            if( k.next[j]!=-1 ){                if( k.data == -1 ) tree[k.next[j]].fail = Root;                else{                    int t = k.fail;                    while( t!=Root && tree[t].next[j]==-1 ) t = tree[t].fail;                    tree[ k.next[j] ].fail = max( tree[t].next[j], Root );                }                q.push(tree[k.next[j]]);            }        }    }}int get_ans(char s[]){    int k=Root, ans = 0;    for(int i=0;s[i];i++){        int t = s[i] - 'a';        while(tree[k].next[t]==-1 && k ) k = tree[k].fail;        k = tree[k].next[t];        if(k==-1){ k = Root;continue;}        int j = k;        while( tree[j].count ){            ans += tree[j].count;            tree[j].count = 0;            j = tree[j].fail;        }        //下面两句很重要,如果走到头以后当前字母不是关键字终点然而其fail指针指向字母是关键字终点的话,        //应当加入此关键值,而网上大多数程序忽视了这一点导致hdu的discuss里反例过不了        ans += tree[ tree[j].fail ].count;        tree[ tree[j].fail ].count = 0;    }    return ans;}char tar[2*N];int main(){    int T,n;    scanf("%d",&T);    while(T--){        scanf("%d",&n);        init(tree[Root],-1);        char a[55];        while(n--){            scanf("%s",a);            Insert(a);        }        AC_automation();        scanf("%s",tar);        printf("%d\n",get_ans(tar));    }    return 0; }
0 0