题目链接

AC自动机

解题思路

AC自动机模板题。

刚学AC自动机,写一篇博客增强理解。

AC自动机最关键的一点在于,\(fail\)失配指针的构造。

\(fail\)指针指向的地方,是匹配出现错误后进行重新匹配的位置,这说明,从根开始到\(fail\)指针指向的地方这一块字符串,正是我们刚刚失配之前配上的那一块字符串(子串),且为最长子串。这一点和KMP算法相同。

AC代码

  1. #include<stdio.h>
  2. #include<string.h>
  3. int ac[100010][26],cnt=1;
  4. int queue[100010],fail[100010],end[100010];
  5. char a[160][75],m[1000010];
  6. struct {
  7. int num,cnt;
  8. }ans[500],temp;
  9. void push(char a[],int l,int num){//建立trie树,很好理解不再赘述
  10. int i,now=0;
  11. for(i=0;i<l;i++){
  12. int v=a[i]-'a';
  13. if(!ac[now][v])ac[now][v]=cnt++;
  14. now=ac[now][v];
  15. }
  16. end[now]=num;
  17. }
  18. void build(){
  19. int head=0,tail=0,i;//C党手写queue
  20. for(i=0;i<26;i++)if(ac[0][i]){
  21. queue[tail++]=ac[0][i];//push
  22. fail[ac[0][i]]=0;
  23. }
  24. while(head<tail){
  25. int v=queue[head++];//pop
  26. for(i=0;i<26;i++){
  27. if(ac[v][i]){
  28. fail[ac[v][i]]=ac[fail[v]][i];
  29. queue[tail++]=ac[v][i];//push
  30. }
  31. else ac[v][i]=ac[fail[v]][i];
  32. //该节点的失配指针,指向该节点的父节点的失配指针所指向的节点的子节点
  33. //也即,假设ac[v][i]的父节点失配指针指向的节点为E,则
  34. //从根节点到E的这个串,为从根节点到v这个串的最长共同结尾子串
  35. //那么,ac[v][i]的失配指针应当指向E的第i个节点(保证这一位字符相同)
  36. //if和else的作用:一个是失配指针,一个是trie图。
  37. //如果这点没有后续了,只能建立trie图。
  38. //否则,应当建立失配指针。
  39. }
  40. }
  41. }
  42. void query(char a[],int l){
  43. int i,j,now=0;
  44. for(i=0;i<l;i++){
  45. now=ac[now][a[i]-'a'];//沿着建立好的trie图走
  46. for(j=now;j;j=fail[j])ans[end[j]].cnt++;//找到单词末尾并存储个数
  47. }
  48. }
  49. //C党手写快排
  50. int cmp(int x,int y){
  51. if(ans[x].cnt>ans[y].cnt)return 1;
  52. if(ans[x].cnt<ans[y].cnt)return 0;
  53. if(ans[x].num<ans[y].num)return 1;
  54. return 0;
  55. }
  56. void qs(int left,int right){
  57. int i=left,j=right;
  58. if(i>=j)return;
  59. while(i!=j){
  60. for(;i<j;j--)if(cmp(j,left))break;
  61. for(;i<j;i++)if(cmp(left,i))break;
  62. if(i!=j){
  63. temp=ans[i];ans[i]=ans[j];ans[j]=temp;
  64. }
  65. }
  66. j=left;
  67. temp=ans[i];ans[i]=ans[j];ans[j]=temp;
  68. qs(left,i-1);
  69. qs(i+1,right);
  70. }
  71. int main(){
  72. int i,n;
  73. while(scanf("%d",&n)){
  74. if(!n)break;
  75. cnt=1;
  76. for(i=1;i<=n;i++){
  77. scanf("%s",a[i]);
  78. push(a[i],strlen(a[i]),i);//建立trie树
  79. ans[i].num=i;
  80. ans[i].cnt=0;
  81. }
  82. build();//构造AC自动机的fail指针,以及完善trie树成为trie图
  83. scanf("%s",m);
  84. query(m,strlen(m));//询问文本串
  85. //以下为本题特色,不是AC自动机精髓,可跳过
  86. qs(1,n);
  87. printf("%d\n",ans[1].cnt);
  88. printf("%s\n",a[ans[1].num]);
  89. for(i=2;i<n;i++){
  90. if(ans[i].cnt-ans[i-1].cnt)break;
  91. printf("%s\n",a[ans[i].num]);
  92. }
  93. memset(end,0,sizeof(int)*cnt);
  94. memset(fail,0,sizeof(int)*cnt);
  95. memset(ac,0,sizeof(ac));
  96. }
  97. return 0;
  98. }

P3796 【模板】AC自动机(加强版) 题解(Aho-Corasick Automation)的更多相关文章

  1. luoguP3796[模板]AC自动机(加强版)

    传送门 ac自动机模板,可能我写的ac自动机是有点问题的,所以跑的有些慢 暴力跳fail统计 代码: #include<cstdio> #include<iostream> # ...

  2. HDU 2222 Keywords Search(AC自动机)题解

    题意:给你几个keywords,再给你一段文章,问你keywords出现了几次. 思路:这里就要用到多模匹配算法AC自动机了,AC自动机需要KMP和字典树的知识,匹配时是在字典树上,失配我们就要用到类 ...

  3. luoguP3808[模板]AC自动机(简单版)

    传送门 ac自动机模板题,裸的多串匹配 代码: #include<cstdio> #include<iostream> #include<algorithm> #i ...

  4. 算法模板——AC自动机

    实现功能——输入N,M,提供一个共计N个单词的词典,然后在最后输入的M个字符串中进行多串匹配(关于AC自动机算法,此处不再赘述,详见:Aho-Corasick 多模式匹配算法.AC自动机详解.考虑到有 ...

  5. 模板 AC自动机

    题目描述 有$N$ 个由小写字母组成的模式串以及一个文本串$T$ .每个模式串可能会在文本串中出现多次.你需要找出哪些模式串在文本串$T$ 中出现的次数最多. 输入输出格式 输入格式: 输入含多组数据 ...

  6. 算法竞赛模板 AC自动机

    AC自动机基本操作 (1) 在AC自动机中,我们首先将每一个模式串插入到Trie树中去,建立一棵Trie树,然后构建fail指针. (2) fail指针,是穿插在Trie树中各个结点之间的指针,顾名思 ...

  7. [模板][P3796]AC自动机(加强版)

    Description: 输出有哪些模式串在文本串中出现次数最多,这个次数是多少 Hint: 多组数据,$ len_{文本串}<=10^6,\sum len_{模式串} <= 70*150 ...

  8. 【模板】AC自动机加强版

    题目大意:给定 N 个模式串和一个文本串,求每个模式串在文本串中出现的次数. 题解:文本串在自动机上匹配的过程中,记录下自动机上每一个状态被访问的次数.对于访问到的节点 i,则状态 i 的后缀中存在的 ...

  9. 洛谷.3808/3796.[模板]AC自动机

    题目链接:简单版,增强版 简单版: #include <cstdio> #include <cstring> const int N=1e6+5,S=26; char s[N] ...

  10. HDU 3065 病毒侵袭持续中(AC自动机)题解

    题意:要你找到主串中每个模式串的个数. 思路:题目都没说是多组数据,结果没while(~)直接WA了,和上一题差不多,可以用map或者开个数组储存.指针要记得回收内存,不然MLE. #include& ...

随机推荐

  1. 使用DTK创建模糊背景窗口并自定义阴影效果

    DTK是deepin开发的基于Qt的开发套件,提供了大量的具有独特风格的美化控件,也提供了很多非常方便的API,下边我们用DTK实现一个模糊窗口,并设置其阴影效果. 使用场景 一切需要模糊窗口作为美化 ...

  2. SPOJ - LCS2 Longest Common Substring II(后缀自动机)题解

    题意: 求\(n\)个串的最大\(LCS\). 思路: 把第一个串建后缀自动机,然后枚举所有串.对于每个串,求出这个串在\(i\)节点的最大匹配为\(temp[i]\)(当前串在这个节点最多取多少), ...

  3. 大数据开发--Hbase协处理器案例

    大数据开发--Hbase协处理器案例 1. 需求描述 在社交网站,社交APP上会存储有大量的用户数据以及用户之间的关系数据,比如A用户的好友列表会展示出他所有的好友,现有一张Hbase表,存储就是当前 ...

  4. JavaScript 设计模式: 发布者-订阅者模式

    JavaScript 设计模式: 发布者-订阅者模式 发布者-订阅者模式 https://github.com/Kelichao/javascript.basics/issues/22 https:/ ...

  5. ES6 Generator vs ES6 async/await

    ES6 Generator vs ES6 async/await next yield promise refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允 ...

  6. Vue Learning Paths

    Vue Learning Paths Vue Expert refs https://vueschool.io/articles/vuejs-tutorials/exciting-new-featur ...

  7. HTTP cache in depth

    HTTP cache in depth HTTP 缓存 https://developers.google.com/web/fundamentals/performance/optimizing-co ...

  8. taro best practice

    taro best practice 最佳实践 https://taro-docs.jd.com/taro/docs/best-practice.html#关于-jsx-支持程度补充说明 https: ...

  9. 翻译:《实用的Python编程》01_06_Files

    目录| 上一节(1.5 列表) | 下一节 (1.7 函数) 1.6 文件管理 大多数的程序需要从某处读取输入.本节讨论文件访问. 文件输入和输出 打开一个文件: f = open('foo.txt' ...

  10. ASP.NET Core中如何对不同类型的用户进行区别限流

    老板提出了一个新需求,从某某天起,免费用户每天只能查询100次,收费用户100W次. 这是一个限流问题,聪明的你也一定想到了如何去做:记录用户每一天的查询次数,然后根据当前用户的类型使用不同的数字做比 ...