突然发现了一篇很棒的讲解ac自动机的文章https://www.cnblogs.com/nullzx/p/7499397.html,补上!~

终于get了一个新算法(。ì _ í。)

自己写了一遍之后结果结果是错的,debug半天才发现有个句子放错位置了,还是不够熟悉吧555

必备算法:KMP(失配时从哪里开始匹配才是最优的)+trie(字典树建树)

ac自动机的图如下:

具体过程我就不是很想讲了,可以看b站的视频,我觉得讲的蛮明白的:传送门

几个关键点:

  • 当前节点的fail指向的是父节点fail下面和当前节点字母相同的节点:比如长字符串是shea,当和she匹配时,因为e后面没有a,所以e这个位置匹配失败,e(最左侧的e)的fail指向的是它的父节点h(最左侧的h)的fail:h(中间的h)下面的e(中间的e),然后在这个新的e(中间的e)的基础上向下匹配,可以匹配到a
  • 节点的fail指向位置的字母和节点对应的字母相同
  • 节点e的fail指向的位置(记为e'),e'的前缀是e前面字符串的后缀,当然也可以是空
  • 建立fail时要先从父节点的fail往下找,找不到再找父节点fail的fail
  • 在计数时每个节点都要算一下它(包括它的fail,fail的fail)的前缀是否是题里给出的单词,是的话将其标志置为-1,避免重复访问。

hdu2222ac代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
const int maxn=1e6+6;
const int maxt=5e5+5;
using namespace std;
struct node{int next[30];int fail,cnt;//cnt记录出现当前节点对应的单词的次数
}state[maxt];queue<int> q;//存字母的编号
int size;
char s[maxn];void init()
{while(!q.empty()) q.pop();for(int i=0;i<maxt;i++){memset(state[i].next,0,sizeof(state[i].next));state[i].cnt=state[i].fail=0;}size=1;//只有根节点
}void insert(char *s)
{int len=strlen(s),now=0;for(int i=0;i<len;i++){int id=s[i]-'a';if(!state[now].next[id]) state[now].next[id]=size++;now=state[now].next[id];}state[now].cnt++;//单词节点
}void build()
{state[0].fail=-1;//根节点q.push(0);while(!q.empty()){int u=q.front();q.pop();for(int i=0;i<26;i++){int now=state[u].next[i];//当前节点的编号if(now)//有这个字母节点{if(u==0) state[now].fail=0;//第一层都指向根节点else{int v=state[u].fail;//父节点的failwhile(v!=-1){if(state[v].next[i]){state[now].fail=state[v].next[i];//指向父节点下面和当前节点字母相同的节点break;}v=state[v].fail;//一直找,父节点fail位置的字母和父节点的字母相同}if(v==-1) state[now].fail=0;//没找到指向根}q.push(now);}}}
}int getnum(int u)
{int ans=0;while(u){if(state[u].cnt!=-1) ans+=state[u].cnt;state[u].cnt=-1;//标记,避免重复访问u=state[u].fail;//顺着fail那条线一直找下去,因为可能第一次fail对应的字符串(这个字符串可以不是给出的单词)的后缀可能是题里给出的单词}return ans;
}int match(char *s)
{int len=strlen(s),now=0,ans=0;for(int i=0;i<len;i++){int id=s[i]-'a';if(state[now].next[id]) now=state[now].next[id];//有当前节点继续往下找else//失配{int p=state[now].fail;while(p!=-1 && state[p].next[id]==0) p=state[p].fail;if(p==-1) now=0;//没找到,回到根,从根开始找s中的下一个字母else now=state[p].next[id];}if(state[now].cnt!=-1)//每次找到一个字母节点都要计算,这个节点可以不是单词节点ans+=getnum(now);}return ans;
}
//输出字典树上字母的编号和fail,检查build是否正确
/*void out()
{cout<<"编号:"<<"fail:"<<endl;queue<int> qq;qq.push(0);while(!qq.empty()){int x=qq.front();qq.pop();for(int i=0;i<26;i++){if(state[x].next[i]){cout<<state[x].next[i]<<"    "<<state[state[x].next[i]].fail<<endl;qq.push(state[x].next[i]);}}}
}*/
int main()
{//freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);int t;scanf("%d",&t);while(t--){init();int n;scanf("%d",&n);for(int i=0;i<n;i++){scanf("%s",s);insert(s);}build();//建fail// out();scanf("%s",s);printf("%d\n",match(s));}return 0;
}

【算法笔记+HDU2222】AC自动机(统计一个长字符串由多少个不同的短字符串组成)相关推荐

  1. ac自动机 匹配最长前缀_AC自动机算法

    AC自动机简介: 首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一.一个常见的例子就是给出n个单词,再给出一段包 ...

  2. 算法学习:AC自动机

    [定义] [自动机]  由 状态集 ,初始状态集 ,终止状态集 ,字母集 ,对应关系五个元素组成的结构   可以简单的将状态集理解为结点,初始状态集理解为初始点,终止状态集理解为终点 字母集理解为一个 ...

  3. 学习笔记:AC自动机

    话说AC自动机有什么用......我想要自动AC机 AC自动机简介:  首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配 ...

  4. 算法讲解:ac自动机及简单衍生

    AC自动机简介:  首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一.一个常见的例子就是给出n个单词,再给出一段 ...

  5. ac自动机 匹配最长前缀_Aho Corasick自动机结合DoubleArrayTrie极速多模式匹配

    本文使用Double Array Trie实现了一个性能极高的Aho Corasick自动机,应用于分词可以取得1400万字每秒,约合27MB/s的分词速度.其中词典为150万词,构建耗时1801 m ...

  6. ac自动机 匹配最长前缀_别再暴力匹配字符串了,高效的KMP,才是真的香

    如果你想了解KMP算法,请静下心读完这篇文章,一定不会辜负你的时间 暴力匹配(BF) 字符串匹配是我们在编程中常见的问题,其中从一个字符串(主串)中检测出另一个字符串(模式串)是一个非常经典的问题,当 ...

  7. HDU2222(AC自动机模版题)

    AC自动机是Trie树和KMP的结合物,但是其实KMP在这里体现了思想,而Trie树才是最重要的,要想学懂AC自动机,学习Trie树是必须的,这些是自己在学习AC自动机的个人看法,我也是在网上学习了大 ...

  8. 长链接(url)转换为短字符串,再把url和短字符串存数据库(有短域名方案)

    import org.apache.commons.codec.digest.DigestUtils;/*** 工具类:通过加密运算后,将长连接转换为短字符串**/ public class Shor ...

  9. 数据结构与算法之美笔记——基础篇(下):图、字符串匹配算法(BF 算法和 RK 算法、BM 算法和 KMP 算法 、Trie 树和 AC 自动机)

    图 如何存储微博.微信等社交网络中的好友关系?图.实际上,涉及图的算法有很多,也非常复杂,比如图的搜索.最短路径.最小生成树.二分图等等.我们今天聚焦在图存储这一方面,后面会分好几节来依次讲解图相关的 ...

  10. AC自动机算法及模板

    AC自动机算法及模板 2016-05-08 18:58 226人阅读 评论(0) 收藏 举报  分类: AC自动机(1)  版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 关于 ...

最新文章

  1. 音视频编解码的国际标准
  2. Scala教程之:Either
  3. 深入Javascript中apply、call、bind
  4. 引号吃掉了我的数据~~~
  5. hive 修改分区备注_Hive分区、分桶操作及其区别
  6. Bailian4045 与3和5无关的数【进制+模除】
  7. 关闭appleid双重认证_如何查看并移除登陆过Apple ID的设备
  8. Unity中的pingpong效果
  9. maven 报错 Failed to execute goal on project ...: Could not resolve dependencies for project ...
  10. 软件工程 实践者的研究方法 第12章答案
  11. AHRS(航姿参考系统)和IMU(惯性测量单元)的区别
  12. 客户旅行地图教程 - 带15个示例
  13. delete和delete[]的理解
  14. Clickhouse导数工具waterdrop用法
  15. outlook查看图片错位异常问题
  16. 真实吐槽点评:华为nova8SE和华为nova7Pro区别-哪个更值得入手-参数对比
  17. python中numpy模块下的np.clip()的用法
  18. 云计算机英语怎么说,云用英语怎么说
  19. 如何防止自己的云服务器被暴力破解密码(限制暴力破解并发送邮件到自己的邮箱)
  20. 联阳(ITE)IT66021FN:HDMI转RGB芯片 3D 资料

热门文章

  1. 通过WDS功能扩大无线网范围
  2. linux设备数内核选项,linux内核设备树修改指南 / linux kernel device tree modify guide
  3. PHP获取grpc请求时间,Go gRPC进阶-超时设置(六)
  4. css颜色跟背景总结(内含实例及截图)
  5. 1.VUE 安装以及vue.js下的第一个hello world
  6. NTKO word在线文本编辑控件写页眉页脚
  7. 全是干货:MBR分区结构以及GPT分区结构
  8. windows10:检测windows defender是不是已经连接到了云安全中心
  9. tf.nn的conv2d卷积与max_pool池化
  10. 苹果:我们从未向中国政府透露源代码