【AC自动机详解+入门模板】HDU 2222

AC自动机模板+例题(HDU2896+HDU3065+HDU2222) 病毒侵袭中(HDU2896) #include<map> #include<cmath> #include<queue> #include<vector> #include<cstdio> #include<string> #include<cstdlib> #include<cstring> ... 阅读详情

第一次写AC自动机,发现也不是太难理解,可能自己以前看过KMP&Trie而且理解的比较透彻吧,看自动机没有太大的困难,因为它也是利用了KMP的思想,理解了KMP,再看自动机就不难了:)

转一下这个blog的描述先,感觉看起来比较好理解,可是他的代码就不敢恭维。。。http://www.cppblog.com/mythit/archive/2011/10/21/80633.html(有改动)

补充一句:自动机的复杂度是O(m+n+z),其中z为主串中模式串的总个数,适合多模式串匹配。

AC自动机算法详解

首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一。一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。要搞懂AC自动机,先得有模式树(字典树)Trie和KMP模式匹配算法的基础知识。AC自动机算法分为3步:构造一棵Trie树,构造失败指针和模式匹配过程。
     如果你对KMP算法和了解的话,应该知道KMP算法中的next函数(shift函数或者fail函数)是干什么用的。KMP中我们用两个指针i和j分别表示,A[i-j+ 1..i]与B[1..j]完全相等。也就是说,i是不断增加的,随着i的增加j相应地变化,且j满足以A[i]结尾的长度为j的字符串正好匹配B串的前 j个字符,当A[i+1]≠B[j+1],KMP的策略是调整j的位置(减小j值)使得A[i-j+1..i]与B[1..j]保持匹配且新的B[j+1]恰好与A[i+1]匹配,而next函数恰恰记录了这个j应该调整到的位置。同样AC自动机的失败指针具有同样的功能,也就是说当我们的模式串在Tire上进行匹配时,如果与当前节点的关键字不能继续匹配的时候,就应该去当前节点的失败指针所指向的节点继续进行匹配。
      看下面这个例子:给定5个单词:say she shr he her,然后给定一个字符串yasherhs。问一共有多少单词在这个字符串中出现过。我们先规定一下AC自动机所需要的一些数据结构,方便接下去的编程。

const int kind = 26;
struct node {
    node *fail;//失败指针
    node *next[kind];//Trie每个节点的子节点(最多26个子母)
    int cnt;//是否为该单词的最后一个节点
    node () {//构造函数初始化
        fail = NULL;
        cnt = 0;
        memset(next,NULL,sizeof(next));
    };
};
char str[55];//输入的单词
char ss[M];//输入的主串
queue<node*> qq;//队列构造失败指针

有了这些数据结构之后,就可以开始编程了:
    首先,将这5个单词构造成一棵Trie,如图-1所示。

 

//建Trie树
void BuildTree (node *root) {
    node *p = root;
    int i = 0,id;
    while (str[i]) {
        id = str[i] - 'a';
        if (p->next[id] == NULL) {
            p->next[id] = new node();
        }
        p = p->next[id];
        i++;
    }
    (p->cnt)++;
}

在构造完这棵Trie之后,接下去的工作就是构造下失败指针。构造失败指针的过程概括起来就一句话:设这个节点上的字母为C,沿着他父亲的失败指针走,直到走到一个节点,他的儿子中也有字母为C的节点。然后把当前节点的失败指针指向那个字母也为C的儿子。如果一直走到了root都没找到,那就把失败指针指向root。具体操作起来只需要:先把root加入队列(root的失败指针指向自己或者NULL),这以后我们每处理一个点,就把它的所有儿子加入队列,队列为空。

//bfs求失败指针
void bfs(node *root) {
    while (!qq.empty()) qq.pop();
    int i;
    root->fail = NULL;
    qq.push(root);
    node *tmp,*p;
    while (!qq.empty()) {
        tmp = qq.front();
        qq.pop();
        p = NULL;
        for (i = 0; i < 26; i++) {
            if (tmp->next[i] != NULL) {
                p = tmp->fail;
                while (p && !p->next[i]) {
                    p = p->fail;
                }
                if (!p) tmp->next[i]->fail = root;
                else tmp->next[i]->fail = p->next[i];
                qq.push(tmp->next[i]);
            }
        }
    }
}

 从代码观察下构造失败指针的流程:对照图-2来看,首先root的fail指针指向NULL,然后root入队,进入循环。第1次循环的时候,我们需要处理2个节点:root->next[‘h’-‘a’](节点h) 和 root->next[‘s’-‘a’](节点s)。把这2个节点的失败指针指向root,并且先后进入队列,失败指针的指向对应图-2中的(1),(2)两条虚线;第2次进入循环后,从队列中先弹出h,接下来p指向h节点的fail指针指向的节点,也就是root;进入第13行的循环后,p=p->fail也就是p=NULL,这时退出循环,并把节点e的fail指针指向root,对应图-2中的(3),然后节点e进入队列;第3次循环时,弹出的第一个节点a的操作与上一步操作的节点e相同,把a的fail指针指向root,对应图-2中的(4),并入队;第4次进入循环时,弹出节点h(图中左边那个),这时操作略有不同。在程序运行到14行时,由于p->next[i]!=NULL(root有h这个儿子节点,图中右边那个),这样便把左边那个h节点的失败指针指向右边那个root的儿子节点h,对应图-2中的(5),然后h入队。以此类推:在循环结束后,所有的失败指针就是图-2中的这种形式。


  最后,我们便可以在AC自动机上查找模式串中出现过哪些单词了。匹配过程分两种情况:(1)当前字符匹配,表示从当前节点沿着树边有一条路径可以到达目标字符,此时只需沿该路径走向下一个节点继续匹配即可,目标字符串指针移向下个字符继续匹配;(2)当前字符不匹配,则去当前节点失败指针所指向的字符继续匹配,匹配过程随着指针指向root结束。重复这2个过程中的任意一个,直到模式串走到结尾为止。

//AC自动机主程序
int AC_run(node *root) {
    int i = 0,ans = 0,id;
    node *p = root;
    while (ss[i]) {
        id = ss[i] - 'a';
        while (!p->next[id] && p != root) {
            p = p->fail;
        }
        p = p->next[id];
        if (!p) p = root;
        node *tmp = p;
        while (tmp != root && tmp->cnt != -1) {
            ans += tmp->cnt;
            tmp->cnt = -1;
            tmp = tmp->fail;
        }
        i++;
    }
    return ans;
}

对照图-2,看一下模式匹配这个详细的流程,其中模式串为yasherhs。对于i=0,1。Trie中没有对应的路径,故不做任何操作;i=2,3,4时,指针p走到左下节点e。因为节点e的count信息为1,所以cnt+1,并且讲节点e的count值设置为-1,表示改单词已经出现过了,防止重复计数,最后temp指向e节点的失败指针所指向的节点继续查找,以此类推,最后temp指向root,退出while循环,这个过程中count增加了2。表示找到了2个单词she和he。当i=5时,程序进入第5行,p指向其失败指针的节点,也就是右边那个e节点,随后在第6行指向r节点,r节点的count值为1,从而count+1,循环直到temp指向root为止。最后i=6,7时,找不到任何匹配,匹配过程结束。


HDU 2222题可以作为AC自动机的模板题

贴上代码

#include <map>
#include <set>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <string>
#include <time.h>
#include <cstdio>
#include <math.h>
#include <iomanip>
#include <cstdlib>
#include <limits.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;

#define LL long long
#define MIN INT_MIN
#define MAX INT_MAX
#define PI acos(-1.0)
#define FRE freopen("input.txt","r",stdin)
#define FF freopen("output.txt","w",stdout)
#define N 10005
#define M 1000005
const int kind = 26;
struct node {
    node *fail;//失败指针
    node *next[kind];//Trie每个节点的子节点(最多26个子母)
    int cnt;//是否为该单词的最后一个节点
    node () {//构造函数初始化
        fail = NULL;
        cnt = 0;
        memset(next,NULL,sizeof(next));
    };
};
char str[55];//输入的单词
char ss[M];//输入的模式串
queue<node*> qq;//队列构造失败指针
//建Trie树
void BuildTree (node *root) {
    node *p = root;
    int i = 0,id;
    while (str[i]) {
        id = str[i] - 'a';
        if (p->next[id] == NULL) {
            p->next[id] = new node();
        }
        p = p->next[id];
        i++;
    }
    (p->cnt)++;
}
//bfs求失败指针
void bfs(node *root) {
    while (!qq.empty()) qq.pop();
    int i;
    root->fail = NULL;
    qq.push(root);root->fail = NULL;
    node *tmp,*p;
    while (!qq.empty()) {
        tmp = qq.front();
        qq.pop();
        p = NULL;
        for (i = 0; i < 26; i++) {
            if (tmp->next[i] != NULL) {
                p = tmp->fail;
                while (p && !p->next[i]) {
                    p = p->fail;
                }
                if (!p) tmp->next[i]->fail = root;
                else tmp->next[i]->fail = p->next[i];
                qq.push(tmp->next[i]);
            }
        }
    }
}
//AC自动机主程序
int AC_run(node *root) {
    int i = 0,ans = 0,id;
    node *p = root;
    while (ss[i]) {
        id = ss[i] - 'a';
        while (!p->next[id] && p != root) {
            p = p->fail;
        }
        p = p->next[id];
        if (!p) p = root;
        node *tmp = p;
        while (tmp != root && tmp->cnt != -1) {
            ans += tmp->cnt;
            tmp->cnt = -1;
            tmp = tmp->fail;
        }
        i++;
    }
    return ans;
}
int main () {
    int t;
    scanf("%d",&t);
    while (t--) {
        int n;
        scanf("%d",&n);
        node *root = new node();
        while (n--) {
            scanf("%s",str);
            BuildTree(root);
        }
        bfs(root);
        scanf("%s",ss);
        printf("%d\n",AC_run(root));
    }
    return 0;
}


loadStop的原因导致的SSUSP Total内存值是可用来调度的可用内存,当前可用内存为 0M。 loadSched和loadStop的阈值是根据 Total 内存和节点内存来做限制的。 loadStop 50G,现在有大量作业SSUSP,说明之前某个时间点该节点内存可能有低于50G的时候,导致作业SSUSP,具体是否是这个原因引起的需要用 bjobs -l JobID 看下作业的详细信息。 如果是loadStop的原因导致的 SSUSP,根据loadStop设置的阈值,Total 值高于loadStop值后,将逐步恢复挂起的作业 阅读详情

相关推荐

技术前沿:半导体前道检测和量测设备修复技术

半导体前道检测设备是目前除光刻机外,国产渗透率较低的环节之一,近年来我国初步实现国产突破。前道检测相对后道检测环节壁垒更高,国内多家涉及后道测试,涉及前道检测和中道检测相对较少。

VOMMA的博客 4544

AC自动机 php代码实现

以下文字都为拷贝,懒,没有第二个原因! ac自动机很神奇,在于这个算法中失配指针的妙处(好比kmp算法中的next数组),说它高深,是因为这个不是一般的算法,而是建立在两个普通算法的基础之上,而这两个算法就是kmp与字典树。所以,如果在看之前,你还不会字典树或者kmp算法,那么请先学习字典树或者kmp算法之后再来看 理论请前往这里,反正很多都可以百度 kmp走起 trie树 数据结构 代码质量不高...

weixin_33877092的博客 698

利用GPAC生成MP4文件

GPAC主要针对学生和内容创作者,代表了一个跨平台的多媒体框架,开发人员可以使用它在 LGPL 许可下制作开源媒体。GPAC多媒体框架兼容范围广泛的流行文件类型,从常见格式(如 AVI、MPEG 和 MOV)到复杂格式(如 MPEG-4 系统或 VRML/X3D)和 360 电影。

深之JohnChen的专栏 1771

ac自动机

下面开始用图学习ac自动机吧(个人比较喜欢放图,能用一张图解决的绝不叨叨) 首先给定模式串"ash","shex","bcd","sha",然后我们根据模式串建立如下trie树: 然后我们再了解下一步: ac自动机,就是在tire树的基础上,增加一个fail指针,如果当前点匹配失败,则将指针转移到fail指针指向的地方,这样就不用回溯,而可以路匹配下去了.(当前模式串后缀和fail指针指向的...

Insistor 714

大模型训练显存瘦身全记录:从ZeRO-3参数分区到CPU Offload的硬件协奏曲

本文详细解析了如何通过ZeRO-3参数分区与CPU/NVMe卸载技术优化大模型训练的显存使用。结合bf16混合精度与梯度累积等策略,实现在消费级GPU上高效训练百亿参数模型,显著提升硬件利用率与训练效率。

weixin_29051245的博客 435

TCGA之GDC-client工具下载安装与使用

文章主要是对GDC-client工具下载TCGA数据库数据整个过程的一个记录 1.下载GDC-client工具 GDC-client工具网址:GDC Data Transfer Tool | NCI Genomic Data Commons (cancer.gov) 我这里下的是上图中红圈中的版本, 2.解压安装 从网上了解的是不能解压到带中文的路径里,解压后是一个.exe文件,为了能直接在cmd命令行下使用,将其加入系统环境: 点击新建之后,输入将文件解压到的路径,然后...

better_strong的博客 1万+

AC自动机详解(转)

(转载自http://www.cppblog.com/mythit/archive/2009/04/21/80633.html)首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一。一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。要搞懂AC自动机,先得有模式树(

幻想の天地 738

Mac Studio M5 Ultra本地部署大模型实战:从内存原理到Ollama开发工作流

大模型推理的性能瓶颈往往不在算力,而在于内存能否装下整个模型、带宽能否持续供得上。Transformer架构每生成一个token都需要把权重完整扫一遍,决定了这本质上是内存密集型任务——统一内存架构因此成为本地部署的关键通路,超大容量与高带宽并行,让“装得下”和“跑得快”同时成立。模型量化技术(如Q4_K_M)则是另一项决定性软件策略,用轻微精度损失换取更低的硬件门槛,也是Ollama本地部署从7B到70B各类模型必做的前置功课。当本地推理服务跑起来后,借助VS Code等开发工具的OpenAI兼容API接

weixin_29043895的博客 454

Leetcode每日一题:116.populating-next-right-pointers-in-each-node(填充每个节点的下一个右侧节点指针)

思路:对整个满二叉树进行层次遍历,同时把每一层的节点连起来now->next=q.front(),当到达该层最后一个结点时(len-1)时,令其指向NULL; /* // Definition for a Node. class Node { public: int val; Node* left; Node* right; Node* next; Node() : val(0), left(NULL), right(NULL), next(NULL) {.

CodeLuweir 的博客 325

将ue4程序嵌入qt界面显示

需求:将ue4程序嵌入qt界面显示 思路:通过使用 windowsAPI 对ue4窗口进行设置跟随qt界面以及活动窗口时的位置层序设置

weixin_44342705的博客 5845

RLHF的数学表示

RLHF(Reinforcement Learning with Human Feedback)是一种结合了强化学习和人类反馈的机器学习方法。它通常用于训练智能体(agent)在复杂环境中做出决策,同时利用人类的反馈来指导和改进学习过程。RLHF 没有一个统一的数学表示式,因为它依赖于具体的应用场景和实现细节。然而,我们可以从强化学习和人类反馈的角度来描述RLHF的一些关键数学概念。

xw555666的博客 688

AC自动机

在字典树上加上失配链(也可以叫做失败指针)就可以构成AC自动机,可以用来解决多模式匹配的问题。给定多个模式串P0、P1、……,给定目标串T,问T中包含了哪些P……等等问题。 在AC自动机中,每一个节点都有一个失败指针指向自动机中的另外一个节点;除了根节点,根节点的失败指针指向NULL。假设节点A的失败指针指向节点B,说明节点A的向上的字符串与从根到B的字符串匹配,而且匹配长度是最长的。 如下的A

RBS的专栏 938

油气井管柱力学发展

油气井管柱力学发展 1 石油管柱力学问题的发复杂性 1)油气管柱动力学的非线性 钻井中钻柱在重力、钻压、扭矩、钻井液浮力和井壁约束等作用下,产生三维变形。一方面随井眼轴线的弯曲而弯曲,这一变形被称为管柱的初位移;另一方面,管柱在运动过程中相对井眼轴线也有变形,这种变形被称为计算位移。管柱大变形主要表现在初位移部分,计算位移相对很小。大曲率井眼中管柱产生大挠度,但管柱很长且柔软性较好,变形一般仍保持...

weixin_43831995的博客 951

HDU 2222 ac自动机入门模板题

Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 56619    Accepted Submission(s): 18519 Problem Description In the mod

大咸鱼。。。 440

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

hdu2222(AC自动机入门模板题)

题目链接:https://vjudge.net/problem/HDU-2222 Keywords Search In the modern time, Search engine came into the life of everybody like Google, Baidu, etc. Wiskey also wants to bring this feature to his image retrieval system. Every image have a long descript..

weixin_44757834的博客 321

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

HDU2222 AC自动机 入门模板

HDU 222 Keywords Search AC 自动机入门模板题 调了一下午 因为输入最后一个字符串打成了%d还有两处取反符号打错 WA了无数次血泪史 以后要注意 AC自动机思路: 这个算法的目的:用几个给定的模式串去在一个串 T 中匹配 简单概括实现方式: 1.对所有的模式串建Trie树。 2.从根节点开始建立Fail指针。基本的逻辑如下:buildFail(node

Muruan 394

hdu 2222 ac自动机入门题 可以做模板

Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 25141    Accepted Submission(s): 8224 Problem Description In the modern

hnust_xiehonghao的专栏 8432

AC自动机入门+模板 (HDU 2222)

Aho-Corasick算法是多模式匹配中的经典算法 多模式匹配就是有多个模式串P1,P2,P3…,Pm,求出所有这些模式串在连续文本T1….n中的所有可能出现的位置。 步骤 1.建立模式的Trie 2.给Trie添加失败路径 3.根据AC自动机,搜索待处理的文本 重难点 构造失败指针 设这个节点上的

Rain Stopped的博客 532

HDU 2222 Keywords Search (AC自动机入门 模板)

HDU 2222 Keywords Search (AC自动机入门 模板)

Tc的专栏 1204

AC自动机入门题目(HDU - 2222 )+模板+解释

AC自动机其实就是 字典树+KMP。 最开始的时候我没有刷字典树的题目,所以不是很能理解, 但是刷完字典树之后,对AC自动机得理解就比较简单了。 AC自动机的构造中有3个需要注意的地方: 1、next[i][j] 这个next里面存的值和字典树的是几乎一样的(不过也有些不同,下面我会解释的)。存放的是当前所在第i个节点当下一个出现的字符为j的时候的节点位置。 2、fail[i] 这个和kmp中

落风听雨 360

hdu2222 AC自动机入门 指针型模板

#include #include #include #include #include #include #include #include #include #include #include #include using namespace std; #define maxnode 10000*100 #define sigma_size 26 struct Node

Jackyguo1992的专栏 699

Keywords Search HDU - 2222 (AC自动机模板入门题)

BUG传送门:布呗之路分析:分享在B站上看到的一个AC自动机的一种思想,其实个人感觉这种写法还是不错的,思想挺好的;#include &lt;iostream&gt; #include &lt;algorithm&gt; #include &lt;map&gt; #include &lt;stack&gt; #include &lt;queue&gt; #include &lt;set&gt; #...

布呗之路 258

HDU 2222 Keywords Search(AC自动机入门,模板)

Keywords Search Time Limit : 2000/1000ms (Java/Other) Memory Limit : 131072/131072K (Java/Other) Total Submission(s) : 13 Accepted Submission(s) : 12 Problem Description In the modern time, Searc

南风古 336

CUGB专题训练之数据结构:E - Keywords Search(HDU 2222 AC自动机经典入门模板题)

E - Keywords Search Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Description In the modern time, Search engine came into the life of every

liwei的专栏 1156

字符串-AC自动机(详细图解)

HDU-2222Keywords Search HDU-2896病毒侵袭 HDU-3065病毒侵袭持续中 POJ-2778DNA Sequence HDU-2296Ring AC自动机模板 AC自动机(Aho-Corasick automaton)是KMP的升级版。即KMP是单模匹配算法,处理一个文本串中查找一个模式串的问题;而AC自动机能在一个文本串中同时查找多个不同的模式串,是多模匹配算法。

有一分热,发一分光。 9540

AC自动机 入门练习题

洛谷日报 强势图解AC自动机 https://www.luogu.com.cn/blog/3383669u/qiang-shi-tu-xie-ac-zi-dong-ji AC自动机-多模式匹配算法 https://blog.youkuaiyun.com/xaiojiang/article/details/52299258 AC 自动机 - OI Wiki https://oi-wiki.org/string/ac-automaton/ ...

nefu_ljw的博客 1342
上一篇: 【DP生成回文字符串的最小插入字符数】POJ 1159
下一篇: 【android RelativeLayout 常用属性】
leolin_
博客等级 码龄16年 96粉丝 411原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值