HDU2222 Keywords Search(AC自动机模板)
AC自动机是一种多模式匹配的算法。大概过程如下:
- 首先所有模式串构造一棵Trie树,Trie树上的每个非根结点都代表一个从根出发到该点路径的字符串。
- 然后每个结点都计算出其fail指针的值,这个fail指针就指向这个结点所表示字符串的最长存在的后缀所对应的结点,如果不存在就指向根:计算每个结点的fail用BFS,比如当前结点u出队要拓展并计算其孩子结点的fail,v是其第k个孩子,fail[v]的值就是某个fail[fail[fail...[u]]]存在第k孩子结点其第k个孩子结点,如果不存在fail[v]就等于root。
- 最后主串就往Trie树上跑,在某个Trie树结点失配了就跳转到这个结点fail指针所指的结点继续跑——不过如果匹配了某个模式串这时可能某个模式串的后缀串被忽略了,所以需要用到temp指针,去检查是否有遗漏后缀没匹配。
而这题大概就是给几个模式串,一个主串,问有几个模式串被主串匹配。
AC自动机的模板题。有个可以优化的地方就是某个模式串被匹配了,下一次经过这儿就可以跳过了temp指针的过程了。
代码参考自kuangbin巨的博客,太简洁了(300+ms):
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int tn,ch[][],cnt[],fail[];
void insert(char *s){
int x=;
for(int i=; s[i]; ++i){
int y=s[i]-'a';
if(ch[x][y]==) ch[x][y]=++tn;
x=ch[x][y];
}
++cnt[x];
}
void init(){
memset(fail,,sizeof(fail));
queue<int> que;
for(int i=; i<; ++i){
if(ch[][i]) que.push(ch[][i]);
}
while(!que.empty()){
int x=que.front(); que.pop();
for(int i=;i<;++i){
if(ch[x][i]) que.push(ch[x][i]),fail[ch[x][i]]=ch[fail[x]][i];
else ch[x][i]=ch[fail[x]][i];
}
}
}
int query(char *s){
int x=,res=;
for(int i=; s[i]; ++i){
int tmp=x=ch[x][s[i]-'a'];
while(tmp){
if(cnt[tmp]>=){
res+=cnt[tmp];
cnt[tmp]=-;
}else break;
tmp=fail[tmp];
}
}
return res;
}
char S[],T[];
int main(){
int t,n;
scanf("%d",&t);
while(t--){
tn=;
memset(ch,,sizeof(ch));
memset(cnt,,sizeof(cnt));
scanf("%d",&n);
while(n--){
scanf("%s",T);
insert(T);
}
init();
scanf("%s",S);
printf("%d\n",query(S));
}
return ;
}
另外之前学的指针版本的,指针版本跑得更快(200+ms):
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
typedef struct Node *pNode;
struct Node{
int cnt;
pNode fail,nxt[];
Node(){
cnt=; fail=NULL;
for(int i=;i<;++i) nxt[i]=NULL;
}
};
pNode root;
char S[];
void insert(char *s){
pNode p=root;
for(int i=;s[i];++i){
int index=s[i]-'a';
if(p->nxt[index]==NULL){
p->nxt[index]=new Node;
}
p=p->nxt[index];
}
++p->cnt;
}
void init(){
queue<pNode> que;
que.push(root);
while(que.size()){
pNode y=que.front(); que.pop();
for(int i=;i<;++i){
if(y->nxt[i]==NULL) continue;
if(y==root){
y->nxt[i]->fail=root;
que.push(y->nxt[i]);
continue;
}
pNode x=y->fail;
while(x&&x->nxt[i]==NULL) x=x->fail;
if(x==NULL) y->nxt[i]->fail=root;
else y->nxt[i]->fail=x->nxt[i];
que.push(y->nxt[i]);
}
}
}
int query(){
int res=;
pNode x=root;
for(int i=;S[i];++i){
int index=S[i]-'a';
while(x->nxt[index]==NULL&&x!=root) x=x->fail;
x=x->nxt[index];
if(x==NULL) x=root;
pNode y=x;
while(y!=root){
if(y->cnt>=){
res+=y->cnt;
y->cnt=-;
}else break;
y=y->fail;
}
}
return res;
}
int main(){
int t,n;
char s[];
scanf("%d",&t);
while(t--){
root=new Node;
scanf("%d",&n);
for(int i=;i<n;++i){
scanf("%s",s);
insert(s);
}
scanf("%s",S);
init();
printf("%d\n",query());
}
return ;
}
HDU2222 Keywords Search(AC自动机模板)的更多相关文章
- HDU2222 Keywords Search [AC自动机模板]
Keywords Search Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others ...
- Keywords Search(AC自动机模板)
Keywords Search Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others ...
- Match:Keywords Search(AC自动机模板)(HDU 2222)
多模匹配 题目大意:给定很多个字串A,B,C,D,E....,然后再给你目标串str字串,看目标串中出现多少个给定的字串. 经典AC自动机模板题,不多说. #include <iostream& ...
- hdu 2222 Keywords Search ac自动机模板
题目链接 先整理一发ac自动机模板.. #include <iostream> #include <vector> #include <cstdio> #inclu ...
- POJ2222 Keywords Search AC自动机模板
http://acm.hdu.edu.cn/showproblem.php?pid=2222 题意:给出一些单词,求多少个单词在字符串中出现过(单词表单词可能有相同的,这些相同的单词视为不同的分别计数 ...
- hdu2222 Keywords Search ac自动机
地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=2222 题目: Keywords Search Time Limit: 2000/1000 MS ...
- HDU2222 Keywords Search —— AC自动机
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2222 Keywords Search Time Limit: 2000/1000 MS (Java/O ...
- HDU 2222 Keywords Search(AC自动机模板题)
学习AC自动机请戳这里:大神blog........ 自动机的模板: #include <iostream> #include <algorithm> #include < ...
- HDU 2222 Keywords Search (AC自动机)(模板题)
<题目链接> 题目大意: 给你一些单词,和一个字符串,问你这个字符串中含有多少个上面的单词. 解题分析: 这是多模匹配问题,如果用KMP的话,对每一个单词,都跑一遍KMP,那么当单词数量非 ...
- hdu2222 KeyWords Search AC自动机入门题
/** 链接:http://acm.hdu.edu.cn/showproblem.php?pid=2222 题意:题意:给定N(N <= 10000)个长度不大于50的模式串,再给定一个长度为L ...
随机推荐
- java获得当前文件路径
第一种: File f = new File(this.getClass().getResource("/").getPath()); System.out.println(f); ...
- NOIP 2014 pj & tg
由于我太弱,去了pj组= = ============================== T1: 傻逼暴力 T2: 傻逼暴力+判断+更新 T3: 手画一下就知道了.算出这个点在第几圈,再使劲yy下在 ...
- Kali Linux下破解WIFI密码挂载usb无线网卡的方法
Kali Linux下破解WIFI密码挂载usb无线网卡的方法 时间:2014-10-12 来源:服务器之家 投稿:root 首先我要说的是,wifi密码的破解不是想象中的那么容易,目前还 ...
- OpenStack
[官网]http://www.openstack.org/ [视频教程1]http://blog.csdn.net/u010973404/article/details/16841229 [视频教程2 ...
- 42.旋转数组的最小元素[Get min value of rotated array]
[题目] 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个排好序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5 ...
- php配置文件语法
2013年12月11日 09:21:58 ; The syntax of the file is extremely simple. Whitespace and lines ; beginning ...
- 转MYSQL学习(三) 函数
这一节主要介绍MYSQL里的函数,MYSQL里的函数很多,我这里主要介绍MYSQL里有而SQLSERVER没有的函数 数学函数 1.求余函数MOD(X,Y) MOD(X,Y)返回x被y除后的余数,MO ...
- codeforces B. Sereja and Stairs 解题报告
题目链接:http://codeforces.com/problemset/problem/381/B 题目意思:给定一个m个数的序列,需要从中组合出符合楼梯定义 a1 < a2 < .. ...
- google maps js v3 api教程(3) -- 创建infowindow
原文地址 前面我们学习了地图和标记的创建.那么今天我们来学习怎样在地图上显示一个窗口(infowindow) infowindow构造函数为:InfoWindow(opts?:InfoWindowOp ...
- 铺地毯(luogu 1003)
题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n 张地毯,编号从 1 到n .现在将这些地毯按照编号从小到大的顺序平行于 ...