AC自动机

曾经以为AC自动机是个很难的东西,但本质上,就是Trip+KMP。

AC自动机的运用

用多个模式串来匹配主串。

AC自动机的步骤

1、建立Trie

2、求出fail指针

什么是fail指针?
先看张图。
假设模式串分别为abcd,bcd,cd,d
示意图
其中红色的代表fail指针
fail指针就是指向当前所表示字符串的最长后缀字符串
这个定义不好看……看图理解。
仔细观察会发现和KMP差不多。

预处理fail指针时,用BFS就行了。

3、匹配

也是类似于KMP。
但是要注意,假如现在匹配到Trie中的节点为t,要试着从t开始,跳到t.fail,直到跳到根。在跳的过程中统计答案。

例题

Keywords Search
懒得将题目copy过来了……

代码

using namespace std;
#include <iostream>
#include <cstring>
#include <algorithm>
int n;
char str[53];
struct Node
{
    int c[26];
    int fail;
    int num;
} d[500002];
int cnt;
int q[500002];
char s[1000003];
inline void init();
inline void insert();
inline void build();
inline void ac();
int ans=0;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin>>T;
    while (T--)
    {
        cin>>n;
        init();
        for (int i=1;i<=n;++i)
        {
            cin>>str;
            insert();
        }
        build();
        cin>>s;
        ac();
        cout<<ans<<'
';
    }
    return 0;   
} 
inline void init()
{
    cnt=1;
    memset(d,0,sizeof d);
    d[1].fail=1;
}
inline void insert()
{
    int t=1;
    for (char *p=str;*p;++p)
    {
        int key=*p-'a';
        if (!d[t].c[key])
            d[t].c[key]=++cnt;
        t=d[t].c[key];
    }
    ++d[t].num;
}
inline void build()
{
    d[1].fail=1;
    int h=-1,t=0;
    q[0]=1;
    do
    {
        ++h;
        for (int i=0;i<26;++i)
            if (d[q[h]].c[i])
            {
                if (q[h]!=1)
                {
                    int p=d[q[h]].fail;
                    while (p!=1)
                    {
                        if (d[p].c[i])
                            break;
                        p=d[p].fail;
                    }
                    d[d[q[h]].c[i]].fail=(d[p].c[i]?d[p].c[i]:1);
                }   
                else
                    d[d[q[h]].c[i]].fail=1;
                q[++t]=d[q[h]].c[i];
            }
    }
    while (h!=t);
}
inline void ac()
{
    ans=0;
    int t=1;
    for (char *ch=s;*ch;++ch)
    {
        int key=*ch-'a';
        while (t!=1 && !d[t].c[key])
            t=d[t].fail;
        if (d[t].c[key])
            t=d[t].c[key];
        for (int i=t;i!=1;i=d[i].fail)
            if (d[i].num>=0)
            {
                ans+=d[i].num;
                d[i].num=-1;
            }
            else
                break;
    }
}
原文地址:https://www.cnblogs.com/jz-597/p/11145290.html