AC自动机 - 学习笔记

AC自动机

----多个模板的字符串匹配

字典树Trie加上失配边构成

struct ACauto
{
    int ch[MAXN][26];
    int size;
    int f[MAXN],last[MAXN],val[MAXN],cnt[MAXN];
    //val用来在字典树中的模板串末尾处标记,标记为模板串的序号(从1开始)
    //last后缀链接:结点J沿着失配指针往回走时,遇到的下一个单词尾结点。 

    void init()//初始化
    {
        size=1;//字典树中的节点数
        memset(ch[0],0,sizeof(ch[0]));//字典树
        memset(cnt,0,sizeof(cnt)); //用于统计配对数
    }

    int idx(char c)//用于返回编号
    {
        return c-‘a‘;
    }

    void insert(char *s,int v)//将字符串s插入字典树中,其中v是字符串的编号,从1开始编号
    {
        int u=0,len=strlen(s);
        for (int i=0;i<len;i++)
        {
            int c=idx(s[i]);
            if (!ch[u][c])
            {
                memset(ch[size],0,sizeof(ch[size]));
                val[size]=0;
                ch[u][c]=size++;
            }
            u=ch[u][c];
        }
        val[u]=v;//在字符串末尾做出标记,标记为字符串的编号i
    }

    void print(int j)//用于输出处理
    {
        if (j)
        {
            cnt[val[j]]++;//成功配对数加1
            print(last[j]);
        }
    }

    int getFail()//BFS构造失配函数
    {
        queue <int> q;
        f[0]=0;
        for (int c=0;c<26;c++)//把各个模板的第一个字符压入队列中
        {
            int u=ch[0][c];
            if (u)
            {
                f[u]=0;
                q.push(u);
                last[u]=0;
            }
        }

        while (!q.empty())
        {
            int r=q.front(); q.pop();
            for (int c=0;c<26;c++)
            {
                int u=ch[r][c];
                if (!u)
                {
                    ch[r][c]=ch[f[r]][c];//如果节点不存在,直接链接到->失配边所指向的节点,这样能够化简计算
                    continue;
                }
                q.push(u);
                f[u]=ch[f[r]][c];//构造当前节点的失配函数:如果失配,找到失配点的父亲节点r,父亲沿着失配边f[r]走向下一个节点即可。
                last[u]=val[f[u]]?f[u]:last[f[u]];//构造后缀链接:如果沿失配指针走的节点是尾节点,就标记为失配指针指向的节点,
                                                    //否则标记为其后缀链接的值(类似于递归)。
            }
        }
    }

    void find(char *T)//AC自动机主函数,在文本串T中寻找模板
    {
        int n=strlen(T);
        int j=0;
        for (int i=0;i<n;i++)
        {
            int c=idx(T[i]);//返回字符的编号
            while(j&&!ch[j][c]) j=f[j];//如果字符不存在,即失配,就顺着失配边走,直到可以匹配
            j=ch[j][c];//如果可以匹配,就走向下一个结点
            if (val[j]) print(j);//如果j指向某个模板的尾部则输出
            else if (last[j]) print(last[j]);//后缀链接
        }
    }
}ac;
时间: 2024-11-10 10:56:06

AC自动机 - 学习笔记的相关文章

AC自动机学习笔记

搞了一晚上AC自动机,发现需要先学trie和kmp……都不会啊..于是又去现学KMP和trie..终于基本看懂AC自动机了. #include <iostream> using namespace std; struct node { int next[26];//每一个节点可以扩展到的字母 int fail;//每一个节点的失配指针 int count;//记录每一个可以构成单词的字符串距根节点的深度 void init()//构造 { memset(next, -1, sizeof(nex

hdu2222 Keywords Search &amp; AC自动机学习小结

传送门:http://http://acm.hdu.edu.cn/showproblem.php?pid=2222 思路:AC自动机入门题,直接上AC自动机即可. 对于构建AC自动机,我们要做的只有三件事: 1)构建字典树 2)构建失败指针 3)构建trie图(这道题好像不做这一步也能A...但是这一步不做是会被卡成O(n^2)的...) 1)第一步还是比较好理解的 根是虚根,边代表字母,那么根到终止节点的路径就是一个字符串,这样对于前缀相同的字符串我们就可以省下存公共前缀的空间. 加入一个模式

AC自动机 学习链接

这个地方写得不错:http://www.cppblog.com/mythit/archive/2009/04/21/80633.html 其实AC自动机是借用了KMP的next(fail)来进行实现 具体是在一个Trie(字典树)中来实现的 时间复杂度O(n+k) (k为待处理子串长度) 所以KMP真是一个神奇的算法,特别是next数组的构造.

AC自动机学习小结

AC自动机 简要说明 \(AC\) 自动机,全称 \(Aho-Corasick\ automaton\) ,是一种有限状态自动机,应用于多模式串匹配.在 \(OI\) 中通常搭配 \(dp\) 食用.因为它是状态自动机. 感性理解:在 \(Trie\) 树上加上 \(fail\) 指针.具体的讲解可以去看dalao们的博客(因为我实在是太菜了讲不好). 题目 Keywords Search 题目:给若干个模式串,再给一个文本串,问有几个模式串在文本串中出现过. 板子题.注意一个模式串只被计算一次

AC算法学习笔记

1.算法流程图 (1)    void Init() 此函数是初始化函数,用来给fail数组和goto数组初始化值. (2)    void GotoFunction(string x) 这个函数的作用是生成有限自动机状态转移图. (3) void FailFunction(int target,int k) 这是fail函数,核心内容是求出每个状态的fail值. (4) void UpdateOutput() 这是update输出函数.其作用是更新每个状态的输出值. (5)void Check

AC自动机--summer-work之我连模板题都做不出

这章对现在的我来说有点难,要是不写点东西,三天后怕是就一无所有了. 但写这个没有营养的blog的目的真的不是做题或提升,只是学习学习代码和理解一些概念. 现在对AC自动机的理解还十分浅薄,这里先贴上目前我看过的文章: 深入理解Aho-Corasick自动机算法 AC 自动机学习笔记 AC自动机相比Trie多了失配边,结点到结点间的状态转移,结点到根的状态转移. 这里fail的定义是:使当前字符失配时跳转到另一段从root开始每一个字符都与当前已匹配字符段某一个后缀完全相同且长度最大的位置继续匹配

学习笔记(SAM)

后缀自动机学习笔记 性质 首先,你最好认为每条边是一个字母,每个节点代表一个单词(从t0走到这个点即是此单词的一个后缀). 所有的正向边,从t0出发沿着nex形成的所有正向边构成一个DEG图,而所有的反向边,即link构成一颗t0为根的树,显然,此树上所有点到根形成的后缀都会被其儿子到根形成的后缀所包含 算法实现 首先写个自定义函数,一般都叫sa_extend() 我们默认根t0是0,他的link(父亲)为-1. 首先新申请一个节点cur,我每次将上一个节点叫做last,先将len[cur]=l

浩爷AC自动机快速学习方案

    今天弄完自动机之后,从那天比赛的阴影中爬出来了,猛地一看真不咋滴难,仔细一看这尼玛还不如猛的一看...     必备算法:KMP,字典树(KMP我写了,字典树太简单,就是一个思想,我可以一个图教你做人)     先讲一下字典树:看图     好了,字典树就看酱紫一个图,你要是脑残就装不懂吧!!    下面是AC自动机的正题:     正如KMP中的求next函数是同样的一个原理     节点的属性:二十六个字母的指针,fail指针,其他...     重点:fail指针,我把它叫做同级指

AC自动机笔记

AC自动机 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<queue> 6 #define MAX 100001 7 #define u(n) (n-'a') 8 using namespace std; 9 struct ac{ 10 int son[26],fail,sum; 11 void init(){ 12