算法竞赛模板 AC自动机

AC自动机基本操作

(1) 在AC自动机中,我们首先将每一个模式串插入到Trie树中去,建立一棵Trie树,然后构建fail指针。

(2) fail指针,是穿插在Trie树中各个结点之间的指针,顾名思义,就是当匹配失败的时候,用于引导p指针回溯,就和KMP算法中的next数组道理相同。

#include<bits/stdc++.h>
using namespace std; 
#define MAX 26     //字典树关键字为‘a’~‘b’
char str[1000005]; //主串(文章) 
int n;             //模式串共有n串 

//字典树结点定义 
struct Node
{
    Node*next[MAX];
    Node*fail;
    int sum;
}*qu[500005];
 
void init(Node*root)
{
    for(int i=0;i<MAX;i++)
        root->next[i]=NULL;
}

//向字典树内添加模式串 
void Insert(Node*root,char*ch)
{
    Node*p=root;
    while(*ch)
    {
        int index=*ch-'a'; 
        if(p->next[index]==NULL)
        {
            p->next[index]=(Node*)malloc(sizeof(Node));
            init(p->next[index]);
            p->next[index]->sum=0;
        }
        p=p->next[index];
        ch++;
    }
    p->sum++;
}

//利用模式串 字典树建树 
Node*TrieCreate()
{
    char ch[65];
    Node*root=(Node*)malloc(sizeof(Node));
    init(root);
    for(int i=0;i<n;i++)
    {
        scanf("%s",ch);
        Insert(root,ch);
    }
    return root;
}

//在字典树内构建 失配指针fail 
void BuildFail(Node*root)
{
    int head=0,tail=0,i;
    root->fail=NULL;
    qu[tail++]=root;
    while(head<tail)
    {
        Node*t=qu[head++];
        Node*p=NULL;
        for(i=0;i<26;i++)
        {
            if(t->next[i])
            {
                if(t==root)
                    t->next[i]->fail=root;
                else
                {
                    p=t->fail;
                    while(p)
                    {
                        if(p->next[i])
                        {
                            t->next[i]->fail=p->next[i];
                            break;
                        }
                        p=p->fail;
                    }
                    if(!p)
                        t->next[i]->fail=root;
                }
                qu[tail++]=t->next[i];
            }
        }
    }
}

//AC自动机 ,返回主串中模式串的数量(文章中关键字的数量) 
int AC(Node*root,char*str)
{
    int len=strlen(str),cnt=0;
    Node*p=root;
    while(*str)
    {
        while(p->next[*str-'a']==NULL&&p!=root)p=p->fail;
        p=p->next[*str-'a'];
        p=(p==NULL)?root:p;
        Node*t=p;
        while(t!=root&&t->sum!=-1)
        {
            cnt+=t->sum;
            t->sum=-1;
            t=t->fail;
        }
        str++;
    }
    return cnt;
}
int main()
{
    cin>>n;
    Node*root=TrieCreate();
    scanf("%s",str);
    BuildFail(root);
    printf("%d
",AC(root,str));
    return 0;
}
原文地址:https://www.cnblogs.com/kannyi/p/9488004.html