AC automation 模板
/*
1.对n个字符串构造tire树 insertWord(node *root, char *word);
2.bfs构造fail指针 makeFail(node *root);
3.基于以上两点的查询 query(node *root, char *str);
*/
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
const int N1 = + ;
const int N2 = + ;
char key[N1];
char desc[N2];
struct node
{
node *next[];
int cnt;
node *fail;
node(){for(int i=; i<; ++i) next[i] = NULL; fail = NULL; cnt = ;}
};
void insertWord(node *root)//构造trie树
{
node *cur = root;
int n = strlen(key);
for(int i=; i<n; ++i)
{
int index = key[i] - 'a';
if(cur->next[index] != NULL)
cur = cur->next[index];
else
{
cur->next[index] = new node();
cur = cur->next[index];
}
}
cur->cnt++;
}
void makeFail(node *root)//构造fail指针
{
queue<node*> q;
q.push(root);
node *cur;
while(!q.empty())
{
cur = q.front();
q.pop();
for(int i=; i<; ++i)
{
if(cur->next[i] != NULL)
{
if(cur == root)//与root相连的结点,即第二层的结点的fail指针都是root
cur->next[i]->fail = root;
else
{
node *tmp = cur;
while(tmp->fail != NULL)// why while?
{
if(tmp->fail->next[i] != NULL)
{
cur->next[i]->fail = tmp->fail->next[i];
break;
}
tmp = tmp->fail;
}
if(tmp->fail == NULL)
cur->next[i]->fail = root;
}
q.push(cur->next[i]);
}
}
}
}
int query(node *root)//查询
{
node *cur = root;
node *tmp = NULL;
int i=,cnt=;
while(desc[i])
{
int index = desc[i] - 'a';
while(cur!=root && cur->next[index] == NULL)
cur = cur->fail;
if(cur->next[index] != NULL)
{
cur = cur->next[index];
tmp = cur;
while(tmp != root && tmp->cnt!=)
{
cnt += tmp->cnt;
tmp->cnt = ;
tmp = tmp->fail;
}
}
i++;
}
return cnt;
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
node *root = new node();
scanf("%d",&n);
for(int i=; i<n; ++i)
{
scanf("%s",key);
insertWord(root);
}
makeFail(root);
scanf("%s",desc);
int ans = query(root);
printf("%d\n",ans);
}
return ;
}
//多串匹配,n个模式字符串构成AC自动机,然后目标串去匹配,看目标串中有多少个模式串
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
/*
根结点的fail指针为NULL,根结点的直接子结点的fail指针为root,很明显,当一个字符都不匹配时,从根结点再开始匹配
每个结点的fail指针都是由它父结点的fail指针决定的。
*/
const int N = + ;
struct node
{
node *next[],*fail;
int cnt;
node(){for(int i=; i<; ++i) next[i] = NULL; fail = NULL; cnt = ;}
};
void insertWord(node *root, char *word)
{
node *cur = root;
int i = ;
while(word[i])
{
int index = word[i] - 'a';
if(cur->next[index] == NULL)
cur->next[index] = new node();
cur = cur->next[index];
++i;
}
cur->cnt ++;
}
char str[N];
void makeFail(node *root)
{
node *cur,*tmp;
queue<node*> q;
q.push(root);
while(!q.empty())
{
cur = q.front();
q.pop();
for(int i=; i<; ++i)
{
if(cur->next[i] != NULL)
{
q.push(cur->next[i]);
if(cur == root)//如果当前结点是root,那么它的直接孩子结点的fail指针指向root
cur->next[i]->fail = root;
else
{
tmp = cur;
while(tmp->fail != NULL)//because root->fail == NULL,如果到了这个地步,说明当前字符串没有后缀
{
if(tmp->fail->next[i] != NULL)
{
cur->next[i]->fail = tmp->fail->next[i];
break;
}
tmp = tmp->fail;
}
if(tmp->fail == NULL)
cur->next[i]->fail = root;
}
}
}
}
} // how to query???
int query(node *root, char *str)
{
node *cur = root;
node *tmp = NULL;
int i = , cnt = ;
while(str[i])
{
int index = str[i] - 'a';
while(cur!=root && cur->next[index]==NULL)//如果失配,那么直接跳到fail指针处去匹配
cur = cur->fail;
if(cur->next[index] != NULL)
{
cur = cur->next[index];//如果当前字符匹配成功,则跳到那个字符,
tmp = cur;
//这就是为什么Ac自动机效率高的缘故,根据fail指针,跳到当前字符串的最长后缀去
//如果tmp->cnt != 0 说明存在该最长后缀形成的字符串
while(tmp->cnt!=)
{
cnt += tmp->cnt;
tmp->cnt = ;
tmp = tmp->fail;
}
}
++i;
}
return cnt;
}
int main()
{
int t,n;
scanf("%d",&t);
char word[];
while(t--)
{
node *root = new node();
scanf("%d",&n);
for(int i=; i<n; ++i)
{
scanf("%s",word);
insertWord(root, word);
}
scanf("%s",str);
makeFail(root);
int ans = query(root, str);
printf("%d\n",ans);
}
return ;
给定n个模式串,长度均不超过m,和一个目标串(长度为L),问目标串中包含多少个模式串(可重叠
的)。
暴力算法是一个个模式串去与目标串匹配,时间复杂度是O(n*m*L)
有更好的算法是AC自动机,时间复杂度是O(n)(这个怎么算来着??)
AC自动机分为两步,1.构建trie树。2.构建fail指针。正是这个fail指针将时间复杂度给大大缩小了
fail指针是匹配失败时,该跳到那个结点去重新匹配
fail指针是指向当前字符串的最长后缀,比如she的fail指针应该指向he或e或root(即指向存在的最长后
缀)
所以当前结点的fail指针由父结点的fail指针所决定
学习资料:http://www.cppblog.com/menjitianya/archive/2014/07/10/207604.html
AC automation 模板的更多相关文章
- HDU 2222 AC自动机模板题
题目: http://acm.hdu.edu.cn/showproblem.php?pid=2222 AC自动机模板题 我现在对AC自动机的理解还一般,就贴一下我参考学习的两篇博客的链接: http: ...
- Match:Keywords Search(AC自动机模板)(HDU 2222)
多模匹配 题目大意:给定很多个字串A,B,C,D,E....,然后再给你目标串str字串,看目标串中出现多少个给定的字串. 经典AC自动机模板题,不多说. #include <iostream& ...
- HDU 3065 (AC自动机模板题)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3065 题目大意:多个模式串,范围是大写字母.匹配串的字符范围是(0~127).问匹配串中含有哪几种模 ...
- HDU 2896 (AC自动机模板题)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2896 题目大意:多个模式串.多个匹配串.其中串的字符范围是(0~127).问匹配串中含有哪几个模式串 ...
- HDU 2222(AC自动机模板题)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2222 题目大意:多个模式串.问匹配串中含有多少个模式串.注意模式串有重复,所以要累计重复结果. 解题 ...
- HDU 2222 (AC自动机模板题)
题意: 给一个文本串和多个模式串,求文本串中一共出现多少次模式串 分析: ac自动机模板,关键是失配函数 #include <map> #include <set> #incl ...
- hdu 2222 Keywords Search ac自动机模板
题目链接 先整理一发ac自动机模板.. #include <iostream> #include <vector> #include <cstdio> #inclu ...
- KMP与AC自动机模板
HDU 1711 Number Sequence(KMP模板题) http://acm.hdu.edu.cn/showproblem.php?pid=1711 #include<bits/std ...
- HDU3695(AC自动机模板题)
题意:给你n个字符串,再给你一个大的字符串A,问你着n个字符串在正的A和反的A里出现多少个? 其实就是AC自动机模板题啊( ╯□╰ ) 正着query一次再反着query一次就好了 /* gyt Li ...
随机推荐
- Xamarin 安装教程 支持Visual Studio 2013
本文的前提是你已经正确的安装了VS 2013. 本文的全部步骤在Win7 Ultimate 64系统上測试通过.支持VS 2013,我用的版本号是VS 2013 update2. 安装 1. ...
- 呜呼!Node.js是什么?
近期看到非常多站点都使用node.js.開始感到非常好奇.就開始推測这是个什么东西,大概就是个js文件吧,所以開始根本 没有在意,可是越感觉就认为越不正确劲,为什么大家都在用它呢?所以我决定搞个明确. ...
- RIO包 健壮的I/O函数代码
下面是关于 #include <stdio.h> #include <string.h> #include <errno.h> #include <sys/t ...
- Ubuntu下Chromium源码的编译
一.失败的经历 印象中,谷歌建议Ubuntu建议版本为10.4.但是我找不到出处了,模糊的印象.不知道是不是这样? 1.Ubuntu10.4.3-desktop-amd64 + Virtual Box ...
- Xcode免证书真机调试,解决cannot read entitlement data问题
本文是根据某个帖子写的(帖子链接在最后放出),但是在配置的过程中,遇到了一个纠结的问题,这个问题折腾了我N久,一直没搞明白到底是什么原因,问题如下: 按照原帖上写的每一步去做了,但是在最后编译的时候出 ...
- 如何搭建NTP服务(转)
最近,在搭建Oracle RAC过程中,需要用到DNS和NTP,其中,DNS用于域名.IP管理,NTP用于时间同步.其实,很久以前搭建过这两种服务,但技术,本质上,符合“用进废退”的客观规律.用得越频 ...
- Android 调用谷歌语音识别
調用谷歌语音识别其实很简单,直接利用 intent 跳转到手机里面的谷歌搜索 代码也很简单,直接调用方法 startVoiceRecognitionActivity() 如果大家手机里面没有谷歌搜索, ...
- hdu-4833-Best-Financing(DP)
Best Financing Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- 如何解决This system is not registered with RHN.
今天我必须写下这篇文章,由于在我刚刚接触到Linux下安装oracle时碰到了Linux中少xscreensaver.rpm包自己弄了非常久.最后还是被一个大哥帮我攻克了:仅仅能说非常的感谢你! 我试 ...
- Axure RP 实践.1
工作需要设计产品原型,找来Axure RP帮忙,看了一些文章,其中下面这段话深得我心. “只使用Axure的默认控件(Wireframe),不要用那些样式花哨的自定义控件,并且所有页面中使用的颜色不能 ...