首页 > 其他 > 详细

AC自动机

时间:2020-07-13 23:57:57      阅读:77      评论:0      收藏:0      [点我收藏+]

AC来自一个大佬的名字,并不是写了就可以自动AC的意思 XD

AC自动机是建立在trie树上的一种优化手段。trie在每次查询一个字符串时,如果在一个子树查不到就会回溯再查,效率会很低。我们考虑在给每个节点加一个如果查不到就跳转的指针fail,那么如果找不到的话直接跳转到fail就可以了。fail代表的是拥有该点的最大后缀的点的位置。

那么怎么寻找这个fail呢?因为我们要寻找最大后缀,深度就是一个比较重要的条件。于是我们bfs。注意了,设一个点now,tmp为now的子节点(从a到z任何一个),有以下推导:

(第一段使用结构体存储了点,第二段是用数组)

e[tmp].fail=e[e[now].fail].nxt[i];
fail[tmp]=ch[fail[now]][i];

首先我们知道trie是有一个0节点的。那么0连接的所有点的fail就连接的是0。如果我们接下来遍历每个点,对于任何点的fail都是其父节点的fail的子字符。因为是bfs,所以这样做一定是正确的而且一定会找到其最长后缀的点。

这里注意一下:如果now点有该字符是按照上面记录的。如果没有(ch[now][i]==0)就需要转移记录一下nxt:

e[now].nxt[i]=e[e[now].fail].nxt[i];
ch[now][i]=ch[fail[now]][i];

这样的话我们查询的时候只需要令now不断等于当前点的nxt就可以快速遍历啦~如果遍历到0,说明就end了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define register R
using namespace std;
namespace ysr
{
    inline int read()
    {
        int w=0,x=0;char c=getchar();
        while(!isdigit(c))w|=c==-,c=getchar();
        while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
        return w?-x:x;
    }
    
    const int maxn=2333;
    int cnt=0;
    int n;
    char s[1000010];
    struct tree{
        int nxt[26],fail,cnt;
        bool vis;
        void init()
        {
            memset(nxt,0,sizeof nxt);
            fail=cnt=0;
            vis=0;
        }
    }e[maxn];
    
    inline int get(char c)
    {
        return c-a;
    }
    
    inline void insert(char *s)
    {
        int now,tmp,t;
        for(now=0;*s;s++)
        {
            t=get(*s);
            if(!e[now].nxt[t])
            {
                e[++cnt].init();
                e[now].nxt[t]=cnt;
            }
            now=e[now].nxt[t];
        }
        e[now].cnt++;
    }
    int ans=0;
    inline void match(char *s)
    {
        int now,tmp;
        for(now=0;*s;s++)
        {
            int t=get(*s);
            now=e[now].nxt[t];
            for(tmp=now;tmp and !e[tmp].vis;tmp=e[tmp].fail){
                ans+=e[tmp].cnt;
                e[tmp].vis=1;
            }
        }
    }
    
    inline void build()
    {
        int now=0;
        queue<int>q;
        while(!q.empty())
        {
            int t=q.front();q.pop();
            for(int i=0;i<26;i++)
            {
                if(e[now].nxt[i]){
                    int tmp=e[now].nxt[i];
                    if(now)
                        e[tmp].fail=e[e[now].fail].nxt[i];
                    q.push(tmp);
                }else 
                e[now].nxt[i]=e[e[now].fail].nxt[i];
            }
        }
    }
    
    inline void work()
    {
        n=read();
        e[0].init();
        while(n--)
        {
            scanf("%s",s);
            insert(s);
        }
        scanf("%s",s);
        match(s);
        printf("%d\n",ans);
    }
}
int main()
{
    ysr::work();
    return 0;
}

 

AC自动机

原文:https://www.cnblogs.com/BrotherHood/p/13296309.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!