{模板}AC自動機

先貼一個大白書的代碼
來自這篇blog

//HDU2222
#include <queue>    
#include <cstdio> 
#include <cstring>
#include <iostream> 
#include <algorithm>
using namespace std;  
const int N=500500;  
struct ACautomachine
{  
    int chd[N][26];//孩子節點編號
    int cnt[N];//當前結點 表示字符串個數
    int fail[N];//失配指針
    int last[N],sz,ans;//題目需要  
    void init()  
    {  
        sz=1,ans=0;  
        memset(cnt,0,sizeof(cnt));  
        memset(fail,0,sizeof(fail));  
        memset(chd[0],0,sizeof(chd[0]));  
    }  
    void insert(char* p)//構建trie  
    {  
        int cur=0;  
        for(;*p;p++)  
        {  
            if(!chd[cur][*p-'a'])  
            {  
                memset(chd[sz],0,sizeof(chd[sz]));  
                chd[cur][*p-'a']=sz++;  
            }  
            cur=chd[cur][*p-'a'];  
        }  
        cnt[cur]++;  
    }  
    bool query(char* p)//題目需要
    {  
        int cur=0;  
        for(;*p;p++)  
        {  
            if(!chd[cur][*p-'a']) break;  
            cur=chd[cur][*p-'a'];  
        }  
        return cnt[cur]&&(!(*p));  
    }  
    int getFail()  
    {  
        queue<int> q;  
        fail[0]=0;  
        for(int c=0;c<26;c++)  
        {  
            int u=chd[0][c];  
            if(u)  
            {  
                fail[u]=0/*Null*/;
                q.push(u); 
                last[u]=0;  
            }  
        }  
        while(!q.empty())  
        {  
            int r=q.front();
            q.pop();
            for(int c=0;c<26;c++)  
            {  
                int u=chd[r][c];  
                if(!u)
                {
                    //直接指向 fail 
                    //也就是 把 trie樹 的 chd[fail[r]][c]及其子孫 全部 “複製” 作r點的子孫
                    chd[r][c]=chd[fail[r]][c];
                    continue;
                }
                q.push(u);  
                int v=fail[r]; 
                while(v&&!chd[v][c]) v=fail[v];
                //1. 令指針爲 fail[fa[u]]
                //2. 若指針的一級兒子中存在一點(代表字符)與 u 相同 
                //  則令fail[u] 指向 當前指針的該兒子
                //3. 否則 指針指向 fail[指針] 並重復 2 操作、

                //目的:使得當前點及其到根的路徑(即一個字典串) 與 fail 和fail[fail]... 所代表字典串 後綴相同
                // 從而實現重新匹配

                fail[u]=chd[v][c];  
                last[u]=cnt[fail[u]] ? fail[u] : last[fail[u]];  
            }  
        }  
    }  
    void solve(int j)  //題目需要
    {  
        if(!j) return;  
        if(cnt[j])  
        {  
            ans+=cnt[j];  
            cnt[j]=0;  
        }  
        solve(last[j]);  
    }  
    void find(char* T)  //題目需要
    {  
        int n=strlen(T),j=0;  
        getFail();  
        for(int i=0;i<n;i++)  
        {  
            j=chd[j][T[i]-'a'];  
            if(cnt[j]) solve(j);  
            else if(last[j]) solve(last[j]);  
        }  
    }  
}ac;  

int main()  
{  
    int t,n;  
    char dic[100],str[1100000];  
    scanf("%d",&t);  
    while(t--)  
    {  
        ac.init();  
        scanf("%d",&n);  
        while(n--)  
        {  
            scanf("%s",dic);  
            ac.insert(dic);  
        }  
        scanf("%s",str);  
        ac.find(str);  
        printf("%d\n",ac.ans);  
    }  
    return 0;  
}  

自己的
剛開始一點也不注意常數
TLE了好久啊[淚]

#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define fo(i,x,y) for (int i=(x);i<=(y);++i)
#define fd(i,x,y) for (int i=(x);i>=(y);--i)
#define oo 2139062143
using namespace std;
typedef long long ll;
typedef double db;
const int N=501000,C=27;
int T,n;
int ans;
char dic[55],str[1100000];
struct AcAutoMation{
    int d[N];
    int chd[N][C];
    int ot[N];
    int fail[N],next[N],last[N];
    int bz[N];
    int sz;
    void del(int x)
    {
        next[last[x]]=next[x],last[next[x]]=last[x];
        bz[x]=1;
    }
    void init()
    {
        memset(bz,0,sizeof bz);
        memset(chd[0],0,sizeof chd[0]);
        memset(ot,0,sizeof ot);
        memset(fail,0,sizeof fail);
        sz=0;
    }
    void insert(char *p)
    {
        int tmp=0;
        int len=strlen(p+1);
        fo(i,1,len)
        {
            int now=p[i]-'a';
            if(!chd[tmp][now])
            {   
                chd[tmp][now]=++sz;
                memset(chd[sz],0,sizeof(chd[sz]));  
            }
            tmp=chd[tmp][now];
        }
        ++ot[tmp];
    }
    void Getfail()
    {
        int tmp=0;
        int hd=0,tl=0;
        fo(i,0,25)
        {
            if(chd[0][i]) 
            {
                d[++tl]=chd[0][i];
                fail[chd[0][i]]=0;    
            }
        }
        while(hd++<tl)
        {
            tmp=d[hd];
            fo(i,0,25)
            if(chd[tmp][i])
            {
                d[++tl]=chd[tmp][i];
                int to=fail[tmp];
                while(to!=0&&!chd[to][i]) to=fail[to];
                fail[chd[tmp][i]]=chd[to][i];
                next[chd[tmp][i]]=(ot[chd[tmp][i]])?(fail[chd[tmp][i]]):(next[fail[chd[tmp][i]]]);
            }
        }
    }
    void solve(char *p)
    {
        int tmp=0;
        int len=strlen(p+1);
        fo(i,1,len)
        {
            int now=p[i]-'a',to=tmp;
            while(!chd[to][now]&&to) to=fail[to];
            tmp=chd[to][now];
            for (int pp=tmp;pp;pp=next[pp])
            {
                if(ot[pp])
                { 
                    ans+=ot[pp],ot[pp]=0;            
                }               
            }    
        }
    }
}ac;
int main()
{
    int TT=clock();
    scanf("%d\n",&T);
    while(T--)
    {
        ac.init();
        scanf("%d\n",&n);
        fo(i,1,n)
        {
            scanf("%s\n",dic+1);    
            ac.insert(dic);
        }
        ac.Getfail();
        ans=0;
        scanf("%s\n",str+1);
        ac.solve(str);
        printf("%d\n",ans);
    }
    return 0;
}
發佈了162 篇原創文章 · 獲贊 297 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章