AC自动机果断是神一样的东西,我赶在比赛前学习还是有用的,AC自动机最基本的是可以解决多个模式串在一个长字符串中出现的种类数或次数:

我暂时还是修改大神们的模板的昂

满满个人注释版帮助自己理解版:

 //该程序不能判别相同模式串,因此若模式串重复,答案会将相同模式串当做不同的处理,因此若需要可以用map去重或修改insert
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
const int maxm=; //maxm是总结点数:约为字母数+++ char s[],word[];
int nxt[maxm][],tail[maxm],f[maxm],size; //nxt是结点指向不同字母的结点下标,tail是表示该结点为几个单词的词尾(可能需要计算重复的模式串情况),f是当不匹配时转跳到的结点下标,size是结点数 int newnode(){ //初始化整个trie或建立新的结点时,首先初始化当前结点所指向的26个字母的结点为0,表示暂时还没有指向的字母,然后暂定该结点不是单词尾结点,暂无失配时转跳位置(即转跳到根节点),返回结点标号
memset(nxt[size],,sizeof(nxt[size]));
f[size]=tail[size]=;
return size++;
} void insert(char s[]){ //构造trie,p为当前结点的上一个结点标号,初始为0;x即为当前结点(上个结点标号指向当前字母的结点)标号,若此结点还未出现过,那么就建立这个结点;然后更新p为当前结点标号以便后续操作
int i,p=;
for(i=;s[i];i++){
int &x=nxt[p][s[i]-'a'];
p=x?x:x=newnode();
}
tail[p]++; //此时仅将s串记录,即将s串结尾的结点加1,若无相同模式串,则此操作只会使所有串尾结点的tail值由0变为1,但有相同模式串,则会重复记录,需要去重可以用map或用tail[p]=1;语句来完成
} void makenxt(){ //利用bfs来构造失配指针
int i;
queue<int>q;
f[]=; //先将0结点挂的字母加入队列,失配指针指向0结点
for(i=;i<;i++){
int v=nxt[][i];
if(v){
f[v]=;
q.push(v);
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(i=;i<;i++){
int v=nxt[u][i];
if(!v)nxt[u][i]=nxt[f[u]][i]; //当u结点没有i对应字母,则视为失配,将其指向失配后转跳到的结点所指向的i对应字母
else{
q.push(v); //u结点存在指向i的结点,则将所指向的结点下标加入队列
f[v]=nxt[f[u]][i]; //失配指针指向上个结点失配指针指向结点所挂当前字母的结点
}
}
}
} int query(char s[]){ //查询s串中模式串出现了多少种/次
int ans=,v=;
for(int i=;s[i];i++){
while(v&&!nxt[v][s[i]-'a'])v=f[v]; //先匹配直到没有失配
v=nxt[v][s[i]-'a'];
int tmp=v;
while(tmp){
ans+=tail[tmp];
tail[tmp]=; //这里加这句是为了仅计算出现多少种模式链,而若不加这句则可以计算累计出现多少次
tmp=f[tmp];
}
}
return ans;
} int main(){
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
size=,newnode();
for(int i=;i<n;i++){
scanf("%s",word);
insert(word);
}
makenxt();
scanf("%s",s);
printf("%d\n",query(s));
}
return ;
}

另:加上last数组的版本,last数组可以很大程度上缩短时间,但是也同样要考虑卡空间的问题,另外鹏神也说last比较适用于纯匹配问题,可能套算法的话用处不是非常大:

 // 有nxt数组版本。。该程序不能判别相同模式串,因此若模式串重复,答案会将相同模式串当做不同的处理,因此若需要可以用map去重或修改insert
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
const int maxm=; //maxm是总结点数:约为字母数+++ char s[],word[];
int nxt[maxm][],tail[maxm],f[maxm],size; //nxt是结点指向不同字母的结点下标,tail是表示该结点为几个单词的词尾(可能需要计算重复的模式串情况),f是当不匹配时转跳到的结点下标,size是结点数
int last[maxm]; //last指针是指向上一个是单词结尾的结点,由于是由失配指针拓展得到的,因此所指向的单词都是该结点表示的单词的后缀单词,但由于可能卡空间,所以虽然可以在时间上优化,但是有时并不使用 int newnode(){ //初始化整个trie或建立新的结点时,首先初始化当前结点所指向的26个字母的结点为0,表示暂时还没有指向的字母,然后暂定该结点不是单词尾结点,暂无失配时转跳位置(即转跳到根节点),返回结点标号
memset(nxt[size],,sizeof(nxt[size]));
f[size]=tail[size]=;
return size++;
} void insert(char s[]){ //构造trie,p为当前结点的上一个结点标号,初始为0;x即为当前结点(上个结点标号指向当前字母的结点)标号,若此结点还未出现过,那么就建立这个结点;然后更新p为当前结点标号以便后续操作
int i,p=;
for(i=;s[i];i++){
int &x=nxt[p][s[i]-'a'];
p=x?x:x=newnode();
}
tail[p]++; //此时仅将s串记录,即将s串结尾的结点加1,若无相同模式串,则此操作只会使所有串尾结点的tail值由0变为1,但有相同模式串,则会重复记录,需要去重可以用map或用tail[p]=1;语句来完成
} void makenxt(){ //利用bfs来构造失配指针
int i;
queue<int>q;
f[]=;
for(i=;i<;i++){ //首先将0结点(根节点)连接的字母结点加入队列,并定失配指针和last指针都指向0结点
int v=nxt[][i];
if(v){
f[v]=last[v]=;
q.push(v);
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(i=;i<;i++){
int v=nxt[u][i];
if(!v)nxt[u][i]=nxt[f[u]][i]; //当u结点没有i对应字母,则视为失配,将其指向失配后转跳到的结点所指向的i对应字母
else{
q.push(v); //u结点存在指向i的结点,则将所指向的结点下标加入队列
f[v]=nxt[f[u]][i]; //设置这个结点的失配指针指向上个结点失配后的指向字母i的结点,由于bfs一定会从字典树浅层到深层,即从字符串短到长,而失配转跳后表示的字符串长度严格减少,所以只需要指向一次即可
last[v]=tail[f[v]]?f[v]:last[f[v]]; //若失配指针指向的结点是单词结尾,那么当前结点失配后就可以直接指向失配结点,即失配路径上的上一个单词结点,若失配结点不是单词结尾,就指向失配结点的last
}
}
}
} int query(char s[]){ //查询s串中模式串出现了多少种/次
int ans=,v=;
for(int i=;s[i];i++){
while(v&&!nxt[v][s[i]-'a'])v=f[v];
v=nxt[v][s[i]-'a'];
int tmp=v;
while(tmp){
ans+=tail[tmp];
tail[tmp]=; //这里加这句是为了仅计算出现多少种模式链,而若不加这句则可以计算累计出现多少次
tmp=last[tmp];
}
}
return ans;
} int main(){
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
size=,newnode();
for(int i=;i<n;i++){
scanf("%s",word);
insert(word);
}
makenxt();
scanf("%s",s);
printf("%d\n",query(s));
}
return ;
}

并没有注释复制可以用用用版:

 #include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
const int maxm=; char s[],word[];
int nxt[maxm][],tail[maxm],f[maxm],size;
int last[maxm]; int newnode(){
memset(nxt[size],,sizeof(nxt[size]));
f[size]=tail[size]=;
return size++;
} void insert(char s[]){
int i,p=;
for(i=;s[i];i++){
int &x=nxt[p][s[i]-'a'];
p=x?x:x=newnode();
}
tail[p]++;
} void makenxt(){
int i;
queue<int>q;
f[]=;
for(i=;i<;i++){
int v=nxt[][i];
if(v){
f[v]=last[v]=;
q.push(v);
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(i=;i<;i++){
int v=nxt[u][i];
if(!v)nxt[u][i]=nxt[f[u]][i];
else{
q.push(v);
f[v]=nxt[f[u]][i];
last[v]=tail[f[v]]?f[v]:last[f[v]];
}
}
}
} int query(char s[]){
int ans=,v=;
for(int i=;s[i];i++){
while(v&&!nxt[v][s[i]-'a'])v=f[v];
v=nxt[v][s[i]-'a'];
int tmp=v;
while(tmp){
ans+=tail[tmp];
tail[tmp]=;
tmp=last[tmp];
}
}
return ans;
} int main(){
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
size=,newnode();
for(int i=;i<n;i++){
scanf("%s",word);
insert(word);
}
makenxt();
scanf("%s",s);
printf("%d\n",query(s));
}
return ;
}

字符串匹配--AC自动机模板的更多相关文章

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

    多模匹配 题目大意:给定很多个字串A,B,C,D,E....,然后再给你目标串str字串,看目标串中出现多少个给定的字串. 经典AC自动机模板题,不多说. #include <iostream& ...

  2. HDU 3065 (AC自动机模板题)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3065 题目大意:多个模式串,范围是大写字母.匹配串的字符范围是(0~127).问匹配串中含有哪几种模 ...

  3. HDU 2896 (AC自动机模板题)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2896 题目大意:多个模式串.多个匹配串.其中串的字符范围是(0~127).问匹配串中含有哪几个模式串 ...

  4. 从0开始 数据结构 AC自动机 模板(from kkke)

    AC自动机模板 2.4.1 头文件&宏&全局变量 #include <queue> #define MAXN 666666 #define MAXK 26//字符数量 st ...

  5. HDu-2896 病毒侵袭,AC自动机模板题!

    病毒侵袭 模板题,不多说了.. 题意:n个不同的字符串分别代表病毒特征,给出m次查询,每次一个字符串(网址),求这个字符串中有几个病毒特征,分别从大到小输出编号,最后输出所有的带病毒网址个数.格式请看 ...

  6. HDU 2222 AC自动机模板题

    题目: http://acm.hdu.edu.cn/showproblem.php?pid=2222 AC自动机模板题 我现在对AC自动机的理解还一般,就贴一下我参考学习的两篇博客的链接: http: ...

  7. HDU 2222(AC自动机模板题)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2222 题目大意:多个模式串.问匹配串中含有多少个模式串.注意模式串有重复,所以要累计重复结果. 解题 ...

  8. HDU 2222 (AC自动机模板题)

    题意: 给一个文本串和多个模式串,求文本串中一共出现多少次模式串 分析: ac自动机模板,关键是失配函数 #include <map> #include <set> #incl ...

  9. hdu 2222 Keywords Search ac自动机模板

    题目链接 先整理一发ac自动机模板.. #include <iostream> #include <vector> #include <cstdio> #inclu ...

随机推荐

  1. nginx File not found 错误

    使用php-fpm解析PHP,"No input file specified","File not found"是令nginx新手头疼的常见错误,原因是php ...

  2. python--HTTPClient接口测试踩坑

    1.今天下午做接口测试的时候遇到一个奇怪的问题:原因不明 requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisc ...

  3. Phonetics: Lecture Three 语音 第三课 Teacher:Patrick

    元音字母: [u]   put [pʊt]  push [pʊʃ]  full [fʊl]  sugar ['ʃʊgɚ]  cook [kʊk]  look [lʊk]   took [tʊk] (v ...

  4. 『科学计算_理论』PCA主成分分析

    数据降维 为了说明什么是数据的主成分,先从数据降维说起.数据降维是怎么回事儿?假设三维空间中有一系列点,这些点分布在一个过原点的斜面上,如果你用自然坐标系x,y,z这三个轴来表示这组数据的话,需要使用 ...

  5. UVA-10163 Storage Keepers (0-1背包)

    题目大意:有n个仓库,m个应聘者,每人对应一个能力值.一个人可以看多个仓库,一间仓库只能被一个人看.如果一个能力为p的人看k间仓库,那么安全系数为p/k,求出最大的最小安全系数,并且求出在此情况下所有 ...

  6. Vue SSR的渲染性能

    一.前言 前端技术年年有新宠,Vue.js 2.0以其轻量级.渐进式.简洁的语法在MVVM框架中脱颖而出,一经推出便很受业界青睐. 为了提高首屏渲染速度 缓存+直出 是必不可少的.在Vue 1× 时代 ...

  7. EasyGui 学习文档【超详细中文版】

    演示使用 Python 3.3.3 版本 0. 安装 EasyGui 官网:http://easygui.sourceforge.net 最新版: <ignore_js_op> easyg ...

  8. 《Python》 列表、元祖和range

    一.列表: 1.Python基础数据类型之一: 2.其他语言中也有列表的概念,js 数组: 3.可索引,可切片,可加步长: 4.列表可以存储大量的数据: 第一:索引,切片,切片+步长. 第二:增删改查 ...

  9. L1-020 帅到没朋友

    当芸芸众生忙着在朋友圈中发照片的时候,总有一些人因为太帅而没有朋友.本题就要求你找出那些帅到没有朋友的人. 输入格式: 输入第一行给出一个正整数N(≤100),是已知朋友圈的个数:随后N行,每行首先给 ...

  10. 玩转X-CTR100 l STM32F4 l CAN通信

    我造轮子,你造车,创客一起造起来!塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ] X-CTR100控制器STM32F4处理器内置CAN ...