AC自动机,一直以来都以为是一个非常高大上的算法,其实它还真的挺高大上的。

首先来说,ac自动机的思想与kmp类似,需要自己模拟来理解。

给两个博客:

http://www.cppblog.com/menjitianya/archive/2014/07/10/207604.html

https://blog.csdn.net/KXL5180/article/details/88093307

还有bibi上有个挺好的视频可以看一下,有助于理解

板子分为3个部分来:

首先对于需要的数组

int cnt,root;//cnt表示树的某个节点位置;root表示根,其实就是0;
int fail[maxn];//表示上一个他这个字符的位置。
int ch[maxn][30];//用来表示一个新的节点,存的值是下一个字符的位置
int val[maxn];//表示某个节点的有效值,就是以该点串串结尾的个数

1.建树。建立字典树,这里开了静态的空间来装线段树。

int cnt,root; //N=26;
void init(){cnt=0;root=newnode();}int newnode()//建立新的一个节点,并初始化fail指针与val值为0;{for(int i=0;i<N;i++)ch[cnt][i]=0;val[cnt]=fail[cnt++]=0;return cnt-1;}
void insert(char *s)//插入某一个字符串{int len=strlen(s);int u=0;for(int i=0;i<len;i++){int v=s[i]-'a';if(!ch[u][v])//如果有该点就不开新节点ch[u][v]=newnode();//没有就开新节点u=ch[u][v];}val[u]++;//每当加完一个新的字符串,结尾其实就是节点要val值加1,表示这点是某个串串的结束}

2.建立fail指针。

fail指针的意义就是如果找一个点的时候,你可以找他的fail指针找到有相同作用的点,当某个点寻找下一点失败的时候有fail指针引导你下次应该跳转的位置。自己并不能说的很清楚。

可以参考博客:https://blog.csdn.net/u013371163/article/details/60469145

void getfail(){queue<int >q;int u=0;for(int i=0;i<N;i++)//找到连接root节点的点,加入队列fail指针已经是0了不用重新赋值。if(ch[u][i])q.push(ch[u][i]);while(!q.empty())//类似于bfs的搜索方式{u=q.front();q.pop();for(int i=0;i<N;i++){if(ch[u][i])//如果u节点有下对应的(i+‘a’){fail[ch[u][i]]=ch[fail[u]][i];//这个点fail指针就是连接到他父亲的fail指针对应位置下的那个'a'+i字母的位置。//因为假设u点的fail的位置为v,那么v这个点的作用其实同u点,那么ch[v][i]即v下边如果有那个'a'+i字母,那么这个位置之前已经知道了,赋过去就行//如果没有呢,那么其实之前开辟新节点也是处理过的,fail[cnt][i]=0,那么他的fail指针就是指向0,就是根节点。q.push(ch[u][i]);}elsech[u][i]=ch[fail[u]][i];//如果u没有'a'+i这个字母,就把它的位置(注意是位置)直接跳到上边解释的位置,查询的时候模拟一下就知道了}}}

3.查找某个串的匹配串有几种。

int query(char *s)//查询的时候是需要自己模拟一下{int len=strlen(s);int u=0,ans=0;for(int i=0;i<len;i++){int v=s[i]-'a';u=ch[u][v];//找到u下边的'a'+i字母的位置for(int j=u;j&&~val[j];j=fail[j])//fail指针走到根节点,或者某个点走过了{ans+=val[j];//加上某个节点的值,其实就是加上串尾点val[j]=-1;//标记为走过}}return ans;}

AC代码

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<set>
#include<stack>
#include<vector>
#include<map>
#include<queue>
#define myself i,l,r
#define lson i<<1
#define rson i<<1|1
#define Lson i<<1,l,mid
#define Rson i<<1|1,mid+1,r
#define half (l+r)/2
#define inff 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define me(a,b) memset(a,b,sizeof(a))
#define min4(a,b,c,d) min(min(a,b),min(c,d))
#define min3(x,y,z) min(min(x,y),min(y,z))
#define max4(a,b,c,d) max(max(a,b),max(c,d))
#define max3(x,y,z) max(max(x,y),max(y,z))
typedef long long ll;
using namespace std;
const int maxn=5e5+5;
const int maxm=1e6+5;
const int N=26;
struct AC
{int cnt,root;int fail[maxn];int ch[maxn][30];int val[maxn];int newnode(){for(int i=0;i<N;i++)ch[cnt][i]=0;val[cnt]=fail[cnt++]=0;return cnt-1;}void init(){cnt=0;root=newnode();}void insert(char *s){int len=strlen(s);int u=0;for(int i=0;i<len;i++){int v=s[i]-'a';if(!ch[u][v])ch[u][v]=newnode();u=ch[u][v];}val[u]++;}void getfail(){queue<int >q;int u=0;for(int i=0;i<N;i++)//找到连接root节点的点,加入队列fail指针已经是0了不用重新赋值。if(ch[u][i])q.push(ch[u][i]);while(!q.empty())//类似于bfs的搜索方式{u=q.front();q.pop();for(int i=0;i<N;i++){if(ch[u][i])//如果u节点有下对应的(i+‘a’){fail[ch[u][i]]=ch[fail[u]][i];//这个点fail指针就是连接到他父亲的fail指针对应位置下的那个'a'+i字母的位置。//因为假设u点的fail的位置为v,那么v这个点的作用其实同u点,那么ch[v][i]即v下边如果有那个'a'+i字母,那么这个位置之前已经知道了,赋过去就行//如果没有呢,那么其实之前开辟新节点也是处理过的,fail[cnt][i]=0,那么他的fail指针就是指向0,就是根节点。q.push(ch[u][i]);}elsech[u][i]=ch[fail[u]][i];//如果u没有'a'+i这个字母,就把它的位置(注意是位置)直接跳到上边解释的位置,查询的时候模拟一下就知道了}}}int query(char *s)//查询的时候是需要自己模拟一下{int len=strlen(s);int u=0,ans=0;for(int i=0;i<len;i++){int v=s[i]-'a';u=ch[u][v];//找到u下边的'a'+i字母的位置for(int j=u;j&&~val[j];j=fail[j])//fail指针走到根节点,或者某个点走过了{ans+=val[j];//加上某个节点的值,其实就是加上串尾点val[j]=-1;//标记为走过}}return ans;}
}AC;
char str[maxm];
int main()
{int t,n;cin>>t;while(t--){scanf("%d",&n);AC.init();while(n--){scanf("%s",str);AC.insert(str);}AC.getfail();scanf("%s",str);printf("%d\n",AC.query(str));}return 0;
}

Keywords Search AC自动机QAQ相关推荐

  1. HDU 2222 Keywords Search (AC自动机模板题)

    一组数据: 1 3 sss sss sss sss ans:3 #include <cstdio> #include <cstdlib> #include <vector ...

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

    题目链接:点击查看 题目大意:给出n个长度不超过50的模式串,再给出一个长度不超过1e6的主串,问模式串在主串中出现过多少次 题目分析:一开始我以为是求n次KMP,后来才知道这样做的时间复杂度是O(L ...

  3. hdu 2222 Keywords Search AC自动机——多串匹配

    http://acm.hdu.edu.cn/showproblem.php?pid=2222 题意: 给出n个单词,再给出一段包含m个字符的文章,求有多少个单词在文章里出现过. 思路: 才开开始以为简 ...

  4. [hdu2222]Keywords Search(AC自动机)

    题意:给定n个单词,一个字符串,问字符串中出现了多少个单词. 解题关键:AC自动机模板题,注意根据题意,匹配完成之后要置0. 注意char数组也可以用cin, 注意理解AC自动机,不可能在同一层 出现 ...

  5. hdu 2222 Keywords Search ac自己主动机

    点击打开链接题目链接 Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Ja ...

  6. HUD2222 Keywords Serch AC自动机

    传送门 显然这是一道AC自动机的模板题 但是还有一些地方需要注意: 1.多组数据要每次清空数组 2.关键字重复要累加,但是文本重复不能累加,可以打标记解决 #include<cstdio> ...

  7. Keywords Search HDU - 2222(AC自动机模板)

    题意: 给定 n个长度不超过 50的由小写英文字母组成的单词准备查询,以及一篇文章,问:文中出现了多少个待查询的单词.多组数据. 题目: In the modern time, Search engi ...

  8. HDU2222 Keywords Search(AC自动机模板)

    AC自动机是一种多模式匹配的算法.大概过程如下: 首先所有模式串构造一棵Trie树,Trie树上的每个非根结点都代表一个从根出发到该点路径的字符串. 然后每个结点都计算出其fail指针的值,这个fai ...

  9. hdu 2222 Keywords Search(ac自动机)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2222 题意:给你一系列子串,再给你一个主串问你主串一共有几个匹配子串 原来使用字典树写的但数据有点大T ...

最新文章

  1. ​综述 | SLAM回环检测方法
  2. linux如何关闭 lvm管理,Linux之LVM管理
  3. FileNameFilter过滤器的使用和Lambda优化程序
  4. 基础篇--Java IO--概览
  5. Loopback Address
  6. 牛客16464 神奇的幻方
  7. html div转行,转行web前端开发的人有没有未来
  8. 响应式Web设计的9项基本原则
  9. 前端常用功能记录(一)
  10. 《21天学通C语言(第7版)》一2.5 答 疑
  11. 好压 v6.3.11130 绿色纯净版(编程必备软件)
  12. java毕业设计TELL情感社交系统Mybatis+系统+数据库+调试部署
  13. 百度贴吧发帖的方法技巧
  14. 看完你就知道交换机端口该搭配什么光模块了
  15. js打怪升级之路三 点出满天小星星
  16. 从Unix看文言文为什么短
  17. 幼儿-知识与能力【1】
  18. php 到数据库乱码怎么解决方法,php数据库乱码解决方法
  19. 完美的Python代码制作“恐龙跳一跳“小游戏【附带源码 】
  20. PKI学习系列-基本概念

热门文章

  1. python 去除list 里面的重复元素
  2. connot not ensure the target project location exist and is accessible
  3. Leetcode812.Largest Triangle Area最大三角形面积
  4. python3:利用SMTP协议发送QQ邮件+附件
  5. Gradle安装使用以及基本操作
  6. ubuntu 挂载 exfat 格式 U盘 mount:unknown filesystem type ‘exfat‘
  7. 重写浏览器alert解决ios端原生alert出现当前网址的URL
  8. maven nexus 3 third party 构件上传
  9. jQuery-1.9.1源码分析系列(四) 缓存系统
  10. Caused by: java.sql.BatchUpdateException