代码:

  1. #include<iostream>
  2. #include<vector>
  3. #include<cstdio>
  4. #include<queue>
  5. #include<map>
  6. #include<cstdlib>
  7. #include<cmath>
  8. #include<algorithm>
  9. #include<set>
  10. #include<cstring>
  11. using namespace std;
  12. typedef long long ll;
  13. const ll INF=;
  14. const int MAXN=;
  15. int trie[MAXN][]; //i到j的编号
  16. int val[MAXN]; //代表这个节点有多少单词
  17. int fail[MAXN]; //fail指针,意为失配时去的位置
  18. int cnt;
  19. queue<int> q;
  20. void ins(string str){ //添加单词
  21. int last=; //代表着多次失配之后最后跳到的地方
  22. for(int i=;i<(int)str.length();i++){
  23. int v=str[i]-'a';
  24. if(!trie[last][v]) trie[last][v]=++cnt; //如果没有对应的这个节点的话,就加上(标记)
  25. last=trie[last][v]; //将上次的编号记住
  26. }
  27. val[last]++; //单词数+1
  28. }
  29. void build(){
  30. for(int i=;i<;i++) //遍历与根节点连接的点
  31. if(trie[][i]){ //如果有这个字母的儿子
  32. fail[trie[][i]]=; //将fail指针指向根
  33. q.push(trie[][i]); //加入搜索队列
  34.  
  35. }
  36. while(!q.empty()){
  37. int u=q.front();
  38. q.pop();
  39. for(int i=;i<;i++){ //枚举其每个儿子
  40. if(trie[u][i]){ //如果有这个节点
  41. fail[trie[u][i]]=trie[fail[u]][i]; //fail指针指向父节点(当前节点)的fail指针指向的节点的相同字母节点
  42. q.push(trie[u][i]); //加入这个点
  43. }
  44. else{
  45. trie[u][i]=trie[fail[u]][i]; //没有这个点的话将其等同于父节点(当前节点)的fail指针的相同字母节点
  46. }
  47. }
  48. }
  49. }
  50. int query(string str){
  51. int last=,ans=;
  52. for(int i=;i<(int)str.length();i++){
  53. last=trie[last][str[i]-'a']; //获得当前字母,当前位置的编号
  54. for(int j=last;j&&~val[j];j=fail[j]) { //只要没有结尾,就按照fail路线走
  55. ans+=val[j]; //加上以这个节点结尾的单词书亮
  56. val[j]=-; //已经拿走了,所以没有了
  57. }
  58. }
  59. return ans;
  60. }
  61. int main()
  62. {
  63. ios_base::sync_with_stdio(false);
  64. cin.tie();
  65. int n;
  66. cin>>n;
  67. string st;
  68. for(int i=;i<n;i++){
  69. cin>>st;
  70. ins(st); //添加单词
  71. }
  72. build(); //初始化
  73. cin>>st;
  74. cout<<query(st); //输出
  75.  
  76. return ;
  77. }

查看神奇代码

0.容器

大部分人是用struct或者class实现内部的函数,但是作为考场上最倩的仔(雾,我决定使用数组存。

(很不理解为什么要用struct存,OI又不是写工程)

  1. int trie[MAXN][27]; //代表从前、后的编号
  2. int val[MAXN]; //代表这个节点有多少单词
  3. int fail[MAXN]; //fail指针,意为失配时去的位置
  4. int cnt; //当前编号

MAXN是数据的范围,是一个常量

1.插入

插入相当于从根一直走到最后一个字母的位置,没有就插入并赋予它一个新编号

  1. void ins(string str){ //添加单词
  2. int last=0; //代表着多次失配之后最后跳到的地方
  3. for(int i=0;i<(int)str.length();i++){
  4. int v=str[i]-'a';
  5. if(!trie[last][v]) trie[last][v]=++cnt; //如果没有对应的这个节点的话,就加上(标记为新的节点,赋予其新编号)
  6. last=trie[last][v]; //将这次的编号记住,以便下次使用
  7. }
  8. val[last]++; //单词数+1
  9. }

 

2.Build

Build的是Fail指针:

先把所有与根节点连接的点的Fail指针指向根,然后将它们加入队列

然后BFS整棵树:

取出队首,然后将其儿子的Fail指针指向父亲的fail指针指向的相同字母的节点

赋予队首不存在的子节点父亲节点的Fail指针指向的相同字母的节点的编号

  1. void build(){
  2. for(int i=0;i<26;i++) //遍历与根节点连接的点
  3. if(trie[0][i]){ //如果有这个字母的儿子
  4. fail[trie[0][i]]=0; //将fail指针指向根
  5. q.push(trie[0][i]); //加入搜索队列
  6.  
  7. }
  8. while(!q.empty()){
  9. int u=q.front();
  10. q.pop();
  11. for(int i=0;i<26;i++){ //枚举其每个儿子
  12. if(trie[u][i]){ //如果有这个节点
  13. fail[trie[u][i]]=trie[fail[u]][i]; //fail指针指向父节点(当前节点)的fail指针指向的节点的相同字母节点
  14. q.push(trie[u][i]); //加入这个点
  15. }
  16. else{
  17. trie[u][i]=trie[fail[u]][i]; //没有这个点的话将其等同于父节点(当前节点)的fail指针的相同字母节点
  18. }
  19. }
  20. }
  21. }
  22. int query(string str){
  23. int last=0,ans=0;
  24. for(int i=0;i<(int)str.length();i++){
  25. last=trie[last][str[i]-'a']; //获得当前字母,当前位置的编号
  26. for(int j=last;j&&~val[j];j=fail[j]) { //只要没有结尾,就按照fail路线走
  27. ans+=val[j]; //加上以这个节点结尾的单词书亮
  28. val[j]=-1; //已经拿走了,所以没有了
  29. }
  30. }
  31. return ans;
  32. }

  

3.顺序

输入单词

ins

build

输出query

  1. int n;
  2. cin>>n;
  3. string st;
  4. for(int i=0;i<n;i++){
  5. cin>>st;
  6. ins(st); //添加单词
  7. }
  8. build(); //初始化
  9. cin>>st;
  10. cout<<query(st); //输出

  

本模版可以在洛谷P3808 https://www.luogu.org/problemnew/show/P3808提交,已通过

【字符串处理】AC自动机知识点&代码的更多相关文章

  1. 字符串处理-AC自动机

    估计在OJ上刷过题的都会对AC自动机这个名词很感兴趣,同样,记得去年ACM暑期集训的时候,在最后讲到字符串部分,听说了这个算法的名字之后就对于它心向往之,AC正好是Accept的简称,字面意义上的理解 ...

  2. HDU-2222 Keywords Search 字符串问题 AC自动机

    题目链接:https://cn.vjudge.net/problem/HDU-2222 题意 给一些关键词,和一个待查询的字符串 问这个字符串里包含多少种关键词 思路 AC自动机模版题咯 注意一般情况 ...

  3. 字符串(AC自动机):HDU 5129 Yong Zheng's Death

    Yong Zheng's Death Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/O ...

  4. 2017ACM暑期多校联合训练 - Team 8 1006 HDU 6138 Fleet of the Eternal Throne (字符串处理 AC自动机)

    题目链接 Problem Description The Eternal Fleet was built many centuries ago before the time of Valkorion ...

  5. HDU-2896 病毒侵袭 字符串问题 AC自动机

    题目链接:https://cn.vjudge.net/problem/HDU-2896 题意 中文题 给一些关键词和一个字符串,问字符串里包括了那几种关键词 思路 直接套模版 改insert方法,维护 ...

  6. HDU-3065 病毒侵袭持续中 字符串问题 AC自动机

    题目链接:https://cn.vjudge.net/problem/HDU-3065 题意 跟上一道题是几乎一模一样,这次是统计关键词的出现次数 一个相当坑的地方,注意多组样例 思路 套模版 改in ...

  7. 字符串(AC自动机):COCI 2015 round 5 divljak

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAy0AAANaCAIAAAALVTQoAAAgAElEQVR4nOy9X2hbx773PXfrQgQjDq

  8. 字符串:AC自动机

    给出一个字典和一个模式串,问模式串中出现几个字典中的单词 最后一行是大串,之前输入的是小串 #include<iostream> #include<cstdio> using ...

  9. 多模字符串匹配算法之AC自动机—原理与实现

    简介: 本文是博主自身对AC自动机的原理的一些理解和看法,主要以举例的方式讲解,同时又配以相应的图片.代码实现部分也予以明确的注释,希望给大家不一样的感受.AC自动机主要用于多模式字符串的匹配,本质上 ...

随机推荐

  1. <stddef.h>

    Common definitions 定义类型: ptrdiff_t 两指针相减的结果,signed integer size_t sizeof操作符的结果,unsigned integer max_ ...

  2. ZUK 22(Z2131) 免解锁BL 免rec 保留数据 Magisk Xposed 救砖 ROOT ZUI 4.0.199

    >>>重点介绍<<< 第一:本刷机包可卡刷可线刷,刷机包比较大的原因是采用同时兼容卡刷和线刷的格式,所以比较大第二:[卡刷方法]卡刷不要解压刷机包,直接传入手机后用 ...

  3. Zynq7000系列之芯片系统结构概述

    相比较经典的FPGA,Zynq7000系列最大的特点是将处理系统PS和可编程资源PL分离开来,固化了PS系统的存在,实现了真正意义上的SOC(System On Chip). 1.  Zynq7000 ...

  4. Caffe:导入caffePython-PyQt failed

    在另一台电脑上使用caffe python版本,显示 Backend Qt5Agg is interactive backend. Turning interactive mode on.       ...

  5. python笔记之发送邮件

    发送邮件前提:开启邮箱授权码 一.开启授权码(以163邮箱为例) 1.登录163邮箱,点击设置--POP3/SMTP/IMAP,出现设置界面   2. 开启SMTP服务且可以查询SMTP的host地址 ...

  6. HDU-4055 Number String 动态规划 巧妙的转移

    题目链接:https://cn.vjudge.net/problem/HDU-4055 题意 给一个序列相邻元素各个上升下降情况('I'上升'D'下降'?'随便),问有几种满足的排列. 例:ID 答: ...

  7. SQL上门

    学习这个 介绍:SQL 是用于访问和处理数据库的标准的计算机语言.结构化化查询语言! SQL可以分为两大部分:数据操作语言(DML)和数据定义语言(DDL) 数据操作语言:select.update. ...

  8. Cent os常见操作命令

    1.查看防火墙状态:firewall-cmd –-state 2.关闭防火墙:systemctl stop firewalld.service 3.禁止防火墙开机启动:systemctl disabl ...

  9. ganglia3.7.2,web3.7.1安装

    1.准备安装包 ganglia-3.7.2-2.el6.x86_64.rpm ganglia-gmetad-3.7.2-2.el6.x86_64.rpm ganglia-gmond-3.7.2-2.e ...

  10. mode-c++

    /*感谢机房JYW的友情馈赠*/#include <iostream> #include <cstdio> #include <cstring> #include ...