首页 > 其他分享 >AC自动机学习笔记

AC自动机学习笔记

时间:2023-01-01 20:23:37浏览次数:45  
标签:AC int tr cnt 笔记 son ++ str 自动机

AC自动机

一句话概括:

  • \(AC\)自动机\(=Trie+Kmp\)

算法复习

\(Trie\)

Trie

字典树,顾名思义,是一个字典一样的树,结构非常简单,不再赘述。

code

int son[N][26], cnt[N], idx;

void insert(char *str)
{
    int p = 0;
    for (int i = 0; str[i]; i ++ )
    {
        int u = str[i] - 'a';
        if (!son[p][u]) son[p][u] = ++ idx;
        p = son[p][u];
    }
    cnt[p] ++ ;
}

int query(char *str)
{
    int p = 0;
    for (int i = 0; str[i]; i ++ )
    {
        int u = str[i] - 'a';
        if (!son[p][u]) return 0;
        p = son[p][u];
    }
    return cnt[p];
}

\(Kmp\)

字符串匹配问题 \(s\)长文本,\(p\)模式串

暴力算法

for (int i = 1; i <= n; i ++ ) // the beginning
{
    for (int j = 1; j <= m; j ++ )
        if (s[i + j - 1] != p[j])
            break;
    if (j > m) success!
}

\(Kmp\)核心思想:一次匹配失败后,直接跳往最近的可能成功位置继续匹配。

\(next[i]\) 在模式串\(p\)中,以\(p[i]\)结尾的后缀,能够匹配的从一开始的非平凡前缀的最大长度。

code

// the index of s,p begin with 1

void get_ne()
{
    next[0] = next[1] = 0;
    for (int i = 2, j = 0; i <= m; i ++ )
    {
        while (j && p[i] != p[j + 1]) j = ne[j];
        if (p[i] == p[j + 1]) j ++ ;
        ne[i] = j;
    }
}

void kmp()
{
    for (int i = 1, j = 0; i <= n; i ++ )
    {
        while (j && s[i] != p[j + 1]) j = ne[j];
        if (s[i] == p[j + 1]) j ++ ;
        if (j == m)
        {
            j = ne[j];
            success!
        }
    }
}

简单来说,\(AC\)自动机就是\(Trie\)树存每个模式串,然后考虑每个模式串的结尾字符\(ch\),有一个后缀\(suf\)考虑如何去求\(fail\)失配指针(最长后缀,和\(Kmp\)中的\(next\)数组类似)。

可以利用\(BFS\)进行\(fail\)失配指针的求解。由于同时需要记录是否重复,所以我们在多次搜索时会新增一个 \(copy\) 数组。

code

const int N = 1e4 + 10, S = 55, M = 1e6 + 10;

int tr[N * S][26], cnt[N * S];
char str[M];
int q[N * S], ne[B * S];

void init()
{
    memset(tr, 0, sizeof tr);
    memset(cnt, 0, sizeof cnt);
    memset(ne, 0, sizeof ne);
    idx = 0;
}

void insert()
{
    int p = 0;
    for (int i = 0; str[i]; i ++ )
    {
        int t = str[i] - 'a';
        if (!tr[p][t]) tr[p][t] = ++ idx;
        p = tr[p][t];
    }
    cnt[p] ++ ;
}

void build()
{
    int hh = 0, tt = -1;
    for (int i = 0; i < 26; i ++ )
        if (tr[0][i])
            q[ ++ tt] = tr[0][i];

    while (hh <= tt)
    {
        int t = q[hh ++ ];
        for (int i = 0; i < 26; i ++ )
        {
            int p = tr[t][i];
            if (!p) tr[t][i] = tr[ne[t]][i];
            else
            {
                ne[p] = tr[ne[t]][i];
                q[ ++ tt] = p;
            }
        }
    }
}

标签:AC,int,tr,cnt,笔记,son,++,str,自动机
From: https://www.cnblogs.com/sunruize/p/17018524.html

相关文章

  • 2-SAT学习笔记
    \(SAT:satisfaction\)\(SAT\)问题:若干问题\(x_1,x_2,...,x_n\),另有\(m\)个需要满足条件,其中每个命题为真或假,求\(x_1,x_2,...,x_n\)的一种取值。一般\(k-SAT\)问......
  • roapi 基于datafusion+ apache arrow 的多协议api 平台
    roapi是基于datafusion+apachearrow的多协议api平台,基于rust开发参考架构  支持的特性多协议,graphql,restapi,pgsql基于datasusion的查询计划执行数据层......
  • 狂神说Java(零基础)预科班笔记
    前言​以下笔记是根据B站up主遇见狂神说的Java零基础学习视频整理而成,视频链接点这里跳转(狂神说系列Java零基础版)。由于本人推崇费曼学习法,不想要写完一篇笔记之后就直......
  • 3.深入理解Oracle中的latch
    1.串行化概述串行化-数据库系统本身是一个多用户并发处理系统,在同一个时间点上,可能会有多个用户同时操作数据库,多个用户同时在相同的物理位置上写数据时,不能发生......
  • OneStack:Ubuntu 12.04 (或11.10) 一键安装部署OpenStack云计算平台
     OneStack:在Ubuntu12.04(precise)上一键安装部署OpentackEssex提醒:如果你喜欢折腾,喜欢自己一步一步安装各个功能组件和配置conf文件,你可以略过此文。本文工具可以在裸机和虚......
  • 动手深度学习系列笔记
    动手学深度学习在线课程此系列文章为听课所敲代码+笔记,使用jupyternotebook展现目录​​3月20日​​​​3月21日​​​​3月27日​​​​3月28日​​​​4月10日​​​​4......
  • 操作系统OS笔记目录(清华大学)
    简介不得不说想自学学操作系统,清华大学慕课是个不错的选择,但难度比较大,特别是想把慕课的实验部分内容也完成的话。不过如果能把它的实验部分也完成的话,相信你会对操作系统......
  • AcWing第84场周赛
    本蒟蒻第一次AK周赛第一题、最大数量本题使用桶排序代码#include<bits/stdc++.h>usingnamespacestd;intm[10005];intmain(){intn;cin>>n;f......
  • C++ Stack
    C++Stack基本操作头文件#include<stack>常用成员函数push(x)//x压入栈顶top()//返回栈顶元素的引用pop()//弹出栈顶元素empty()//栈为空返回true......
  • 宏碁-A515-51G-51D3 电脑 Hackintosh 黑苹果efi引导文件
    硬件型号驱动情况主板宏碁-A515-51G-51D3处理器i5-8250U已驱动内存8GbDDR4已驱动硬盘SSDM21TBWD730SNWESTERNDIGITAL已驱动显卡IntelUHDGraphics620已驱动声卡Real......