【算法笔记+HDU2222】AC自动机(统计一个长字符串由多少个不同的短字符串组成)
突然发现了一篇很棒的讲解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自动机(统计一个长字符串由多少个不同的短字符串组成)相关推荐
- ac自动机 匹配最长前缀_AC自动机算法
AC自动机简介: 首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一.一个常见的例子就是给出n个单词,再给出一段包 ...
- 算法学习:AC自动机
[定义] [自动机] 由 状态集 ,初始状态集 ,终止状态集 ,字母集 ,对应关系五个元素组成的结构 可以简单的将状态集理解为结点,初始状态集理解为初始点,终止状态集理解为终点 字母集理解为一个 ...
- 学习笔记:AC自动机
话说AC自动机有什么用......我想要自动AC机 AC自动机简介: 首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配 ...
- 算法讲解:ac自动机及简单衍生
AC自动机简介: 首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一.一个常见的例子就是给出n个单词,再给出一段 ...
- ac自动机 匹配最长前缀_Aho Corasick自动机结合DoubleArrayTrie极速多模式匹配
本文使用Double Array Trie实现了一个性能极高的Aho Corasick自动机,应用于分词可以取得1400万字每秒,约合27MB/s的分词速度.其中词典为150万词,构建耗时1801 m ...
- ac自动机 匹配最长前缀_别再暴力匹配字符串了,高效的KMP,才是真的香
如果你想了解KMP算法,请静下心读完这篇文章,一定不会辜负你的时间 暴力匹配(BF) 字符串匹配是我们在编程中常见的问题,其中从一个字符串(主串)中检测出另一个字符串(模式串)是一个非常经典的问题,当 ...
- HDU2222(AC自动机模版题)
AC自动机是Trie树和KMP的结合物,但是其实KMP在这里体现了思想,而Trie树才是最重要的,要想学懂AC自动机,学习Trie树是必须的,这些是自己在学习AC自动机的个人看法,我也是在网上学习了大 ...
- 长链接(url)转换为短字符串,再把url和短字符串存数据库(有短域名方案)
import org.apache.commons.codec.digest.DigestUtils;/*** 工具类:通过加密运算后,将长连接转换为短字符串**/ public class Shor ...
- 数据结构与算法之美笔记——基础篇(下):图、字符串匹配算法(BF 算法和 RK 算法、BM 算法和 KMP 算法 、Trie 树和 AC 自动机)
图 如何存储微博.微信等社交网络中的好友关系?图.实际上,涉及图的算法有很多,也非常复杂,比如图的搜索.最短路径.最小生成树.二分图等等.我们今天聚焦在图存储这一方面,后面会分好几节来依次讲解图相关的 ...
- AC自动机算法及模板
AC自动机算法及模板 2016-05-08 18:58 226人阅读 评论(0) 收藏 举报 分类: AC自动机(1) 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 关于 ...
最新文章
- 音视频编解码的国际标准
- Scala教程之:Either
- 深入Javascript中apply、call、bind
- 引号吃掉了我的数据~~~
- hive 修改分区备注_Hive分区、分桶操作及其区别
- Bailian4045 与3和5无关的数【进制+模除】
- 关闭appleid双重认证_如何查看并移除登陆过Apple ID的设备
- Unity中的pingpong效果
- maven 报错 Failed to execute goal on project ...: Could not resolve dependencies for project ...
- 软件工程 实践者的研究方法 第12章答案
- AHRS(航姿参考系统)和IMU(惯性测量单元)的区别
- 客户旅行地图教程 - 带15个示例
- delete和delete[]的理解
- Clickhouse导数工具waterdrop用法
- outlook查看图片错位异常问题
- 真实吐槽点评:华为nova8SE和华为nova7Pro区别-哪个更值得入手-参数对比
- python中numpy模块下的np.clip()的用法
- 云计算机英语怎么说,云用英语怎么说
- 如何防止自己的云服务器被暴力破解密码(限制暴力破解并发送邮件到自己的邮箱)
- 联阳(ITE)IT66021FN:HDMI转RGB芯片 3D 资料
热门文章
- 通过WDS功能扩大无线网范围
- linux设备数内核选项,linux内核设备树修改指南 / linux kernel device tree modify guide
- PHP获取grpc请求时间,Go gRPC进阶-超时设置(六)
- css颜色跟背景总结(内含实例及截图)
- 1.VUE 安装以及vue.js下的第一个hello world
- NTKO word在线文本编辑控件写页眉页脚
- 全是干货:MBR分区结构以及GPT分区结构
- windows10:检测windows defender是不是已经连接到了云安全中心
- tf.nn的conv2d卷积与max_pool池化
- 苹果:我们从未向中国政府透露源代码