算法导论—AC自动机
华电北风吹
日期:2016-05-03
AC自动机是比较高效的多模式匹配算法。类似于KMP在模式串上的状态转移算法,AC自动机通过在trie树上建立状态转移,使得对匹配串遍历一遍就可以找到所有的模式串。
AC自动机一般有以下三步:首先,对所有的模式串建立trie树。然后,对trie树所有节点以它的最长后缀对应的前缀字符串作为它的失配指针,建立AC自动机。最后一步,对文本串在AC自动机上进行匹配。
题目链接:
http://hihocoder.com/problemset/problem/1036?sid=786758
参考代码:
#include <iostream>
#include <queue>
#include <string>
#include <string.h>
using namespace std;#define size 26struct node
{node *fail; //失败指针node *next[size]; //Tire每个节点有26个子节点,分别对应26个英文字母int count; //该节点是否为单词的末尾节点node(){fail = NULL;count = 0;memset(next, NULL, sizeof(next));}
};void Insert(node *root, string str)
{node *p = root;int i = 0, index;for (int i = 0; i < str.length(); i++){index = str[i] - 'a';if (p->next[index] == NULL)p->next[index] = new node();p = p->next[index];}p->count++;
}
void GetFail(node *root)
{int i;root->fail = NULL;queue<node*> q;q.push(root);while (q.empty() == false){node *temp = q.front();q.pop();node *p = NULL;for (i = 0; i<size; i++){if (temp->next[i] != NULL){if (temp == root)temp->next[i]->fail = root;else{p = temp->fail;while (p != NULL){if (p->next[i] != NULL){temp->next[i]->fail = p->next[i];break;}p = p->fail;}if (p == NULL)temp->next[i]->fail = root;}q.push(temp->next[i]);}}}
}
bool Query(node *root, string str)
{int cnt = 0, index;node *p = root;for (int i = 0; i < str.length(); i++){index = str[i] - 'a';while (p->next[index] == NULL && p != root)p = p->fail;p = p->next[index];p = (p == NULL) ? root : p;node *temp = p;while (temp != root){if (temp->count != 0)return true;elsetemp = temp->fail;}}return false;
}
int main()
{int n;node *root = new node();cin >> n;string keyword;while (n--){cin >> keyword;Insert(root, keyword);}GetFail(root);string str;cin >> str;if (Query(root, str))cout << "YES" << endl;elsecout << "NO" << endl;return 0;
}
上面的代码是理论上正确的代码,但是如果那这个去提交的话会超时,把84行while修改为if以后就可以通过了,但是修改以后逻辑上是错误的代码。
下面给一个AC自动机功能扩展代码:
#include <iostream>
#include <queue>
#include <vector>
#include <string>
#include <string.h>
#include <fstream>
using namespace std;#define size 26struct ACNode
{ACNode *fail; //失败指针ACNode *next[size]; //Tire每个节点有26个子节点,分别对应26个英文字母int count; //该节点是否为单词的末尾节点,也可用于判断模式是否重复int patternNo; //该节点是第几个模式,查找的时候用于还原用于ACNode(){fail = NULL;count = 0;patternNo = -1;memset(next, NULL, sizeof(next));}
};
void Insert(ACNode *root, string str, int patterNo)
{ACNode *p = root;int i = 0, index;for (int i = 0; i < str.length(); i++){index = str[i] - 'a';if (p->next[index] == NULL)p->next[index] = new ACNode();p = p->next[index];}p->count++;p->patternNo = patterNo;
}
void GetFail(ACNode *root)
{int i;root->fail = NULL;queue<ACNode*> q;q.push(root);while (q.empty() == false){ACNode *temp = q.front();q.pop();ACNode *p = NULL;for (i = 0; i<size; i++){if (temp->next[i] != NULL){if (temp == root)temp->next[i]->fail = root;else{p = temp->fail;while (p != NULL){if (p->next[i] != NULL){temp->next[i]->fail = p->next[i];break;}p = p->fail;}if (p == NULL)temp->next[i]->fail = root;}q.push(temp->next[i]);}}}
}
int Query(ACNode *root, string str, vector<string> &keySet)
{int cnt = 0, index;ACNode *p = root;for (int i = 0; i < str.length();i++){index = str[i] - 'a';while (p->next[index] == NULL && p != root)p = p->fail;p = p->next[index];p = (p == NULL) ? root : p;ACNode *temp = p;while (temp != root){if (temp->count>0){int patternNo = temp->patternNo;int patternLength = keySet[patternNo].length();cout << i - patternLength + 1 << " " << keySet[patternNo] << endl;cnt += temp->count;}temp = temp->fail;}}return cnt;
}
int main()
{ifstream in(".\\input.txt");cin.rdbuf(in.rdbuf());int n;ACNode *root = new ACNode();cin >> n;string keyword;vector<string> keySet;for (int i = 0; i < n;i++){cin >> keyword;keySet.push_back(keyword);Insert(root, keyword,i);}GetFail(root);string str;cin >> str;Query(root, str, keySet);return 0;
}
参考博客:
http://www.cppblog.com/mythit/archive/2009/04/21/80633.html
http://www.cnblogs.com/xudong-bupt/p/3433506.html
算法导论—AC自动机相关推荐
- KMP算法、AC自动机算法的原理介绍以及Python实现
KMP算法 要弄懂AC自动机算法,首先弄清楚KMP算法. 这篇文章讲的很好: http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E ...
- AC自动机算法及模板
AC自动机算法及模板 2016-05-08 18:58 226人阅读 评论(0) 收藏 举报 分类: AC自动机(1) 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 关于 ...
- 提高篇 第二部分 字符串算法 第4章 AC自动机
https://blog.csdn.net/wangyh1008/article/details/81428056 [模板]AC自动机(加强版) 洛谷3796 AC自动机_A_loud_name-CS ...
- 数据结构与算法之美笔记——基础篇(下):图、字符串匹配算法(BF 算法和 RK 算法、BM 算法和 KMP 算法 、Trie 树和 AC 自动机)
图 如何存储微博.微信等社交网络中的好友关系?图.实际上,涉及图的算法有很多,也非常复杂,比如图的搜索.最短路径.最小生成树.二分图等等.我们今天聚焦在图存储这一方面,后面会分好几节来依次讲解图相关的 ...
- ac自动机 匹配最长前缀_AC自动机算法
AC自动机简介: 首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一.一个常见的例子就是给出n个单词,再给出一段包 ...
- 【BZOJ】2553: [BeiJing2011]禁忌 AC自动机+期望+矩阵快速幂
[题意]给定n个禁忌字符串和字符集大小alphabet,保证所有字符在集合内.一个字符串的禁忌伤害定义为分割能匹配到最多的禁忌字符串数量(一个可以匹配多次),求由字符集构成的长度为Len的字符串的期望 ...
- hdu 2243(poj2778的加强版!(AC自动机+矩阵))
问你长度为1~N的串中包含了模式串的串总共有几个(先求出总共小于L的单词数(26^1+26^2+26^3+...26^L)..然后再减去不包括所给字符串的单词) 答案要模2^64,直接用unsinge ...
- 【BZOJ】4861: [Beijing2017]魔法咒语 AC自动机+DP+矩阵快速幂
[题意]给定n个原串和m个禁忌串,要求用原串集合能拼出的不含禁忌串且长度为L的串的数量.(60%)n,m<=50,L<=100.(40%)原串长度为1或2,L<=10^18. [算法 ...
- Aho-Corasick 多模式匹配算法(AC自动机) 的算法详解及具体实现
多模式匹配 多模式匹配就是有多个模式串P1,P2,P3-,Pm,求出所有这些模式串在连续文本T1-.n中的所有可能出现的位置. 例如:求出模式集合{"nihao","ha ...
最新文章
- 动态鼠标指针_推荐8款电脑鼠标指针,让你电脑不再千篇一律
- boost::hana::remove_at_c用法的测试程序
- Spring Stateless State Security第3部分:JWT +社会认证
- Objective-C模版方法(TemplateMethod)
- win10雷电3接口驱动_技嘉推出B550 主板首发雷电3接口:40Gbps速率、Intel主控
- 快了!CVPR 2019 所有录用论文题目列表刊出,即将开放下载!
- java弱引用在安卓中有效吗_Android 软引用和弱引用详解及实例代码
- 【自爆系列】如何从整体上削弱一支队伍的技术水平
- SQL 错误: ORA-12910
- SQL语言 --- 数据定义
- PC通过adb连接手机 无需root连接 需要root连接
- java模板引擎哪个好_模板引擎比较
- 容斥原理(转载http://www.cppblog.com/vici/archive/2011/09/05/155103.html)
- 如何撰写和发表SCI论文
- AI,让大海永远蔚蓝如诗
- 坚果云企业版服务器端,坚果云团队版和企业版的区别
- 建木(Jianmu)----迈出建木第一步创建项目分组
- Zcash使用工具nheqminer用cpu挖矿
- KiCAD元件库快速制作
- 全球23家电信巨头布局区块链、数字货币 打响“支付翻身战”