ac自动机最详细的讲解,让你一次学会ac自动机。

ac自动机最详细的讲解,让你一次学会ac自动机。在没学 ac 自动机之前 觉得 ac 自动机是个很神奇 很高深 很难的算法 学完之后发现 ac 自动机确实很神奇 很高深 但是却并不难 我说 ac 自动机很神奇 在于这个算法中失配指针的妙处 好比 kmp 算法中的 next 数组 说它高深 是因为这个不是一般的算法 而是建立在两个普通算法的基础之上 而这两个算法就是 kmp 与字典树 所以 如果在看这篇博客之前 你还不会字典树或者 kmp 算法 那么请先学习字典树或者 km

struct node{ node *next[26]; node *fail; int sum; }; 
void Insert(char *s) { node *p = root; for(int i = 0; s[i]; i++) { int x = s[i] - 'a'; if(p->next[x] == NULL) { newnode=(struct node *)malloc(sizeof(struct node)); for(int j=0;j<26;j++) newnode->next[j] = 0; newnode->sum = 0;newnode->fail = 0; p->next[x]=newnode; } p = p->next[x]; } p->sum++; } 
void build_fail_pointer() { head = 0; tail = 1; q[head] = root; node *p; node *temp; while(head < tail) { temp = q[head++]; for(int i = 0; i <= 25; i++) { if(temp->next[i]) { if(temp == root) { temp->next[i]->fail = root; } else { p = temp->fail; while(p) { if(p->next[i]) { temp->next[i]->fail = p->next[i]; break; } p = p->fail; } if(p == NULL) temp->next[i]->fail = root; } q[tail++] = temp->next[i]; } } } } 
void ac_automation(char *ch) { node *p = root; int len = strlen(ch); for(int i = 0; i < len; i++) { int x = ch[i] - 'a'; while(!p->next[x] && p != root) p = p->fail; p = p->next[x]; if(!p) p = root; node *temp = p; while(temp != root) { if(temp->sum >= 0) { cnt += temp->sum; temp->sum = -1; } else break; temp = temp->fail; } } } 

如果你还没有看懂ac自动机,没关系,细细品味,你一定能成功的。

如果你看懂了上面的讲解,那么我们可以做一道模板题来试试,以hdu2222为例,ac代码如下:

#include 
  
    using namespace std; const int maxn = 1e7 + 5; const int MAX = ; int cnt; struct node{ node *next[26]; node *fail; int sum; }; node *root; char key[70]; node *q[MAX]; int head,tail; node *newnode; char pattern[maxn]; int N; void Insert(char *s) { node *p = root; for(int i = 0; s[i]; i++) { int x = s[i] - 'a'; if(p->next[x] == NULL) { newnode=(struct node *)malloc(sizeof(struct node)); for(int j=0;j<26;j++) newnode->next[j] = 0; newnode->sum = 0;newnode->fail = 0; p->next[x]=newnode; } p = p->next[x]; } p->sum++; } void build_fail_pointer() { head = 0; tail = 1; q[head] = root; node *p; node *temp; while(head < tail) { temp = q[head++]; for(int i = 0; i <= 25; i++) { if(temp->next[i]) { if(temp == root) { temp->next[i]->fail = root; } else { p = temp->fail; while(p) { if(p->next[i]) { temp->next[i]->fail = p->next[i]; break; } p = p->fail; } if(p == NULL) temp->next[i]->fail = root; } q[tail++] = temp->next[i]; } } } } void ac_automation(char *ch) { node *p = root; int len = strlen(ch); for(int i = 0; i < len; i++) { int x = ch[i] - 'a'; while(!p->next[x] && p != root) p = p->fail; p = p->next[x]; if(!p) p = root; node *temp = p; while(temp != root) { if(temp->sum >= 0) { cnt += temp->sum; temp->sum = -1; } else break; temp = temp->fail; } } } int main() { int T; scanf("%d",&T); while(T--) { root=(struct node *)malloc(sizeof(struct node)); for(int j=0;j<26;j++) root->next[j] = 0; root->fail = 0; root->sum = 0; scanf("%d",&N); getchar(); for(int i = 1; i <= N; i++) { gets(key); Insert(key); } gets(pattern); cnt = 0; build_fail_pointer(); ac_automation(pattern); printf("%d\n",cnt); } return 0; } 
  
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/202445.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月20日 上午7:07
下一篇 2026年3月20日 上午7:07


相关推荐

  • robots.txt文件的作用

    robots.txt文件的作用Robots.txt文件的作用:1、屏蔽网站内的死链接。2、屏蔽搜索引擎蜘蛛抓取站点内重复内容和页面。3、阻止搜索引擎索引网站隐私性的内容。因此建立robots.txt文件是很有必要的,网站中重复的内容、页面或者404信息过多,搜索引擎蜘蛛就会认为该网站价值较低,从而降低对该网站的“印象分”,这就是我们经常听到的“降低权重”,这样网站的排名就不好了。robo

    2022年5月8日
    46
  • sstream用法

    sstream用法#include<sstream>stringstream对象用于输入一行字符串,以空格为分隔符把该行分隔开来stringstr=”helloworldIamveryhappy!”;stringstreamsstream(str);…

    2022年5月4日
    95
  • java后端知识概述

    java后端知识概述1,java基础知识包括基本语法,集合类框架,以及java语言的特性,jvm等基本知识点,还有一些高级特性,比如反射,注解等等。2,设计模式设计模式是为了可重用代码,让代码更容易被他人理解、保证代码的可靠性的。通常来说,设计模式在系统开发中都是必不可少的。因为这样会简化,降低系统实现过程中要解决的问题。设计模式是软件工程的基石脉络,而模式是在某一背景下某个问题的一种解决方案。常见的设计模式有工厂模式,单例模式,mvc模式等等。而在开发中,所用到的设计模式,往往会根据实际背景去选择某一设计模式。

    2022年7月7日
    49
  • recvfrom的参数

    recvfrom的参数今天遇到一个奇怪的问题。linux环境下gcc,socket中UDP的recvfrom函数原型ssize_trecvfrom(intsockfd,void*buf,intlen,unsignedintflags,structsockaddr*from,socket_t*fromlen);网上给出的最基本的UDP—echo服务器测试基本的是可以的。…

    2022年7月23日
    13
  • 安徽人工智能“腾云”出海

    安徽人工智能“腾云”出海

    2026年3月14日
    4
  • 朋友圈集赞神器!再也不怕谁让集赞了

    朋友圈集赞神器!再也不怕谁让集赞了这里是「每周分享」的第34期。往期分享内容可以在公众号后台的「不务正业」菜单中找到,Python和机器学习类的文章在另一个「不误正业」菜单中。这一期的话题是:朋友…

    2025年9月17日
    6

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号