【AC自動機】統計單詞出現個數

hz2016評測《==點

caioj.cn《==點
#include<map>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Maxchar 1000000
#define Maxm 10000
#define Maxn 50
#define Maxs 26
#define mes(x,y) memset(x,y,sizeof(x));
#define mpy(x,y) memcpy(x,y,sizeof(x))
#define INF 2147483647
using namespace std;
struct Tire{
    int s,c[Maxs+1],fail;
    Tire(){
        s=fail=0;
        mes(c,-1);
    }
}t[Maxn*Maxm+1];//字典樹 
int T,tot,ans,n;
char a[Maxchar+1];
void clean(int x){
    t[x].s=t[x].fail=0;
    for(int i=1;i<=Maxs;i++)t[x].c[i]=-1;//清空字典樹節點 
}
void bt(int root){
    int x=root,len=strlen(a+1);//建字典樹 
    for(int i=1;i<=len;i++){//len個字符依次建節點 
        int y=a[i]-'a'+1;//把字符換成值 
        if(t[x].c[y]==-1){//如果沒有節點 
            t[x].c[y]=++tot;//給新的節點一個新編號 
            clean(tot);//先給他清空再給節點 
        }
        x=t[x].c[y];//我來新建的節點繼續建 
    }
    t[x].s++;//記錄下再節點這個位置結尾,就是這個字符串的結尾的位置是這個節點的個數,有點囉嗦,自己意會一下。 
}
queue<int> q;
void bfs(){
    q.push(0);
    while(q.empty()==0){//bfs循環找節點 
        int x=q.front();
        for(int i=1;i<=Maxs;i++){
            int son=t[x].c[i];//在樹上做kmp 
            if(son==-1)continue;//找存在的節點 
            if(x==0)t[son].fail=0;
            else{
                int j=t[x].fail;
                while(j!=0&&t[j].c[i]==-1)j=t[j].fail;//fail就是kmp的p數組然後一個一個跳 
                t[son].fail=max(t[j].c[i],0);//看看存不存在,不存在指向0,就是kmp的else p[i]=0; 
            }
            q.push(son); 
        }
        q.pop();
    }
}
void solve(){
    int x=0,len=strlen(a+1),j;
    for(int i=1;i<=len;i++){//在樹上查找 
        int y=a[i]-'a'+1;
        while(x!=0&&t[x].c[y]==-1)x=t[x].fail;//再找一下和這句話有沒有匹配的,有的話++ 
        x=t[x].c[y];
        if(x==-1){x=0;continue;}
        j=x;
        while(t[j].s!=0){
            ans+=t[j].s;//s就是用來記錄有多少個符合的。 
            t[j].s=0;
            j=t[j].fail;
        }
    }
    printf("%d\n",ans);
}
int main(){
    scanf("%d",&T);
    while(T--){
        ans=tot=0;
        scanf("%d",&n);
        clean(0);
        for(int i=1;i<=n;i++){
            scanf("%s",a+1);
            bt(0);
        }
        bfs();
        scanf("%s",a+1);
        solve();
    }
    return 0;
}
這題還是邊看代碼邊理解把,ac自動機是建立在Tire就是字典樹的基礎上,大家可以先去學一下字典樹,可惜暫時沒有字典樹的題。 就先練一下ac自動機吧,noip可能出的(某dalao:不出我當場吃屍米) 所以大家好好背模版。  

查看原文:http://hz2016.tk/blog/?p=25
發佈了127 篇原創文章 · 獲贊 52 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章