AC自動機模板(hdu2222)

剛剛學習了AC 自動機,先記錄一個數組寫法的模板。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define Max 26
#define N 1000005

struct node
{
    int next[Max];//每一個節點可以擴展到的字母
    int fail;//每一個節點的失配指針
    int count;
    void init()//構造
    {
        memset(next,-1,sizeof(next));
        fail=0;
        count=0;
    }
}s[N];
int num;//記錄節點編號
char str[55];//模板串,單詞
char ss[N];//母串
int q[N],tail,head;//隊列相關信息
void cas_init()//在整個程序前構造root
{
    s[0].init();//初始化頭結點
    num=1;//當前的節點數量爲1
}
void insert()
{
    int len=strlen(str);
    int p=0,i,j;
    for(i=0;i<len;i++)
    {
        j=str[i]-'a';//求出字母在next中的編號
        if(s[p].next[j]==-1)//如果爲空則構造新的,否則順着上次的開始往下構造
        {
            s[num].init();//初始化當前節點
            s[p].next[j]=num++;//連向當前節點,並是num++來擴充節點
        }
        p=s[p].next[j];//向下遍歷
    }
    s[p].count++;//增加離根節點這條路徑
}
void build_ac()
{
    tail=head=0;//初始化隊列
    int temp,p;
    for(int i=0;i<Max;i++)
    {
        if(s[0].next[i]!=-1)
        {
            q[tail++]=s[0].next[i];//和根節點相連的都入隊
        }
    }
    while(tail!=head)
    {
        p=q[head++];//記錄隊首節點
        for(int i=0;i<Max;i++)//遍歷首節點的next
        {
            if(s[p].next[i]!=-1)//如果節點next不爲空
            {
                q[tail++]=s[p].next[i];//將兒子節點入隊列
                temp=s[p].fail;//記錄節點的失配指針指向
                while(temp>0&&s[temp].next[i]==-1)//當失配指針不爲root時一直循環找到一的兒子節點不爲空或到了root
                temp=s[temp].fail;
                if(s[temp].next[i]!=-1)//如果當前節點有兒子的話記錄下來備用
                temp=s[temp].next[i];
                s[s[p].next[i]].fail=temp;//是當前節點的失配指針指向剛纔記錄的節點完成失配指針的構造
            }
        }
    }
}
void query()
{
    int len=strlen(ss);
    int p=0;
    int temp=0;
    int ans=0;
    for(int i=0;i<len;i++)
    {
        int id=ss[i]-'a';
        while(p>0&&s[p].next[id]==-1)//當前p指針不是root和找不到兒子時,一直找下去(及kmp的while)
        p=s[p].fail;//一直尋找失配指針
        if(s[p].next[id]!=-1)//找到適合的失配指針
        {
            p=s[p].next[id];//指向這個兒子節點,更新p的值進行下次匹配
            temp=p;
            while(temp>0&&s[temp].count!=-1)//temp > 0表示還沒到root,count != -1表示指針前還有單詞
            {
                ans+=s[temp].count;//加上有的單詞個數
                s[temp].count=-1;//不重複計算
                temp=s[temp].fail;//一直尋找失配指針
            }
        }
    }
    printf("%d\n",ans);
}
int main()
{
    int n;
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        cas_init();
        for(int i=1;i<=n;i++)
        {
            scanf("%s",str);
            insert();
        }
        build_ac();
        scanf("%s",ss);
        query();
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章