AC自动机

AC自动机就是在trie树上的每一个节点上加了一个fail指针,用来多串匹配,类似fail数组。

模板题:hdu2222 给出n个串,然后给一篇文章,问这n个串有多少个在文章里面出现过。

首先我们把这n个串搞成一棵AC自动机,然后在这上面匹配这一篇文章。

image

(盗图一张)

首先我们先建成一棵单纯的trie,然后每个结束节点做点标记啥的。

然后我们来构造失败指针。我们在这颗trie上面bfs。比如我们现在要为一个新节点决定fail指针,如果这个节点上的字母为c,我们就沿着他父亲的失败指针走,直到走到一个节点,他的儿子中也有字母为c的节点。然后把当前节点的失败指针指向那个字母也为c的儿子。如果一直走到了root都没找到,那就把失败指针指向root。然后把这个节点加入队列,然后继续bfs它的孩子。然后如何把一段文字拿去匹配呢?我们开始在root,然后每次往下面匹配一个字符,匹配不到就往fail走。一直到走到某一个节点下面有这个字符了就往下面走,否则就走到root。然后我们把这个节点按照fail遍历一圈,所有这些子串都可以被匹配到。(注意此时不要改变当前节点)

(如果窝讲不清楚这里似乎讲得比较清楚

下面这份代码有一点实现上的技巧,如果一个点的next为空,它就会指向跳若干次fail之后的那个点…具体看代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <limits>
#include <set>
#include <map>
using namespace std;
#define SZ 1000099
int rot=1,ch[SZ][29],fail[SZ],cnt[SZ],e=1;
void insert(char* s)
{
    int cur=rot;
    for(int i=0;s[i];i++)
    {
        int c=s[i]-'a';
        if(!ch[cur][c]) ch[cur][c]=++e;
        cur=ch[cur][c];
    }
    cnt[cur]++;
}
int qs[SZ],h=0,t=0;
void bfail()
{
    h=t=0; fail[rot]=rot;
    for(int i=0;i<26;i++)
    {
        if(!ch[rot][i]) 
        {
            ch[rot][i]=rot; continue;
        }
        fail[ch[rot][i]]=rot;
        qs[t++]=ch[rot][i];
    }
    while(h!=t)
    {
        int cur=qs[h++];
        for(int c=0;c<26;c++)
        {
            if(!ch[cur][c]) ch[cur][c]=ch[fail[cur]][c];
            else
            {
                fail[ch[cur][c]]=ch[fail[cur]][c];
                qs[t++]=ch[cur][c];
            }
        }
    }
}
int match(char* s)
{
    int cur=rot,ans=0;
    for(int i=0;s[i];i++)
    {
        int c=s[i]-'a'; cur=ch[cur][c];
        for(int f=cur;f!=rot;f=fail[f]) ans+=cnt[f], cnt[f]=0;
    }
    return ans;
}
int n,T;
char str[SZ];
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        rot=e=1;
        memset(ch,0,sizeof(ch));
        memset(fail,0,sizeof(fail));
        memset(cnt,0,sizeof(cnt));
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",str);
            insert(str);
        }
        bfail();
        scanf("%s",str);
        printf("%d
",match(str));
    }
}

然后有一个AC自动机的专题里面都是AC自动机有关的题目大家可以做一下:

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=25605#overview

等窝做得差不多了再来贴代码。

UPD:稍微做了几题,弃坑啦。

image

代码可以戳这里看到。(懒得拷上来了

题解可以戳出这套题的神犇博客

原文地址:https://www.cnblogs.com/zzqsblog/p/5308865.html