AC自动机模板

这里仅以hdu 2222的题目的自动机为模板。

该模板来自于http://www.bilibili.com/video/av6295004/index_2.html

#include<bits/stdc++.h>

const int MAX_N = 1e6 + 5;
const int MAX_Tot = 500005;
///Trie + KMP的利用
struct Aho{
    struct state{
        int next[26];
        int fail, cnt;//fail指针指向失配点,失配点一般寻找他父亲节点的失配点。 然后cnt就表示出现的次数
    }stateTable[MAX_Tot];

    int size;
    std::queue<int> que;

    void init(){//初始化
        for (int i = 0; i < MAX_Tot; i++){
            memset(stateTable[i].next, 0, sizeof(stateTable[i].next));
            stateTable[i].fail = stateTable[i].cnt = 0;
        }
        while (!que.empty()) que.pop();
        size = 1;
    }

    void insert(char *S){//构建Trie树
        int n = strlen(S);
        int now = 0;
        for (int i = 0; i < n; i++){
            char c = S[i];
            if (!stateTable[now].next[c - 'a'])
                stateTable[now].next[c - 'a'] = size++;
            now = stateTable[now].next[c - 'a'];
        }
        stateTable[now].cnt++;
    }
    
    //构建AC自动机
    void build(){//由于构建AC自动机是需要提前知道父亲节点的失配指针的,且其他结点的也需要知道。所以这里用bfs,因为失配指针的长度不可能长于目前长度
        stateTable[0].fail = -1;//根节点的是失配指针不存在,所以为-1
        que.push(0);
        while (!que.empty()){
            int u = que.front(); que.pop();
            for (int i = 0; i < 26; i++){
                if (stateTable[u].next[i]){//如果存在子节点的话
                    if (u == 0) stateTable[stateTable[u].next[i]].fail = 0;//根节点的儿子节点的失配全为0
                    else {
                        int v = stateTable[u].fail;
                        while (v != -1){
                            if (stateTable[v].next[i]){//找到失配点
                                stateTable[stateTable[u].next[i]].fail = stateTable[v].next[i];
                                break;
                            }
                            v = stateTable[v].fail;
                        }
                        if (v == -1) stateTable[stateTable[u].next[i]].fail = 0;//没有找到失配点,那么就重新从0开始出发
                    }
                    que.push(stateTable[u].next[i]);
                }
            }
        }
    }

    inline int cal(int u){
        int res = 0;
        while (u){
            res += stateTable[u].cnt;
            stateTable[u].cnt = 0;//因为每个串只需要计算一次,所以这里要对cnt进行清空
            u = stateTable[u].fail;
        }
        return res;
    }

    int match(char *S){
        int n = strlen(S);
        int res = 0, now = 0;
        for (int i = 0; i < n; i++){
            char c = S[i];
            if (stateTable[now].next[c - 'a'])//如果存在子节点,则继续往下搜
                now = stateTable[now].next[c - 'a'];
            else {//如果不存在,则沿失配边走。
                int p = stateTable[now].fail;
                while (p != -1 && stateTable[p].next[c - 'a'] == 0) p = stateTable[p].fail;
                if (p == -1) now = 0;//如果没有找到失配点,则另now = 根节点
                else now = stateTable[p].next[c - 'a'];
            }
            if (stateTable[now].cnt)
                res += cal(now);
        }
        return res;
    }
}aho;

char ch[MAX_N];
原文地址:https://www.cnblogs.com/heimao5027/p/6371126.html