欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

AC自动机

程序员文章站 2022-06-06 17:42:03
...

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

AC自动机的运用

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

AC自动机的步骤

1、建立Trie

2、求出fail指针

什么是fail指针?
先看张图。
假设模式串分别为abcd,bcd,cd,d
AC自动机
其中红色的代表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<<'\n';
    }
    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;
    }
}