AC自动机

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 500001
using 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; 
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章