/*
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 模板的更多相关文章

  1. HDU 2222 AC自动机模板题

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

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

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

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

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

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

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

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

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

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

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

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

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

  8. KMP与AC自动机模板

    HDU 1711 Number Sequence(KMP模板题) http://acm.hdu.edu.cn/showproblem.php?pid=1711 #include<bits/std ...

  9. HDU3695(AC自动机模板题)

    题意:给你n个字符串,再给你一个大的字符串A,问你着n个字符串在正的A和反的A里出现多少个? 其实就是AC自动机模板题啊( ╯□╰ ) 正着query一次再反着query一次就好了 /* gyt Li ...

随机推荐

  1. 回文(manacher)

    裸manacher 我竟然写跪了………… 一个地方(偶数)没写清楚…… 我OOXOXOXOXXOXO #include<cstdio> #include<cstdlib> #i ...

  2. JAVA的反射机制学习笔记(二)

    上次写JAVA的反射机制学习笔记(一)的时候,还是7月22号,这些天就瞎忙活了.自己的步伐全然被打乱了~不能继续被动下去.得又一次找到自己的节奏. 4.获取类的Constructor 通过反射机制得到 ...

  3. How to get the source code of the chromium of the specified revision

    I'd like to get the source code of the chromium 34.0.1847.9. gclient config http://src.chromium.org/ ...

  4. POJ2828 Buy Tickets 【线段树】+【单点更新】+【逆序】

    Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 12296   Accepted: 6071 Desc ...

  5. 开源mp3播放器--madplay 编译和移植 简记

    madplay是一款开源的mp3播放器. http://madplay.sourcearchive.com/ 下面简单记录一下madplay的编译与移植到ARM开发板上的过程 一.编译x86版本的ma ...

  6. API - 微云

    API - 微云 1.接口说明 2.数据上传协议说明 1. 接口说明 文件上传申请,成功会返回实际上传的地址. 根据申请上传返回的地址,组织数据上传. 1.1 URL OAuth2.0协议: http ...

  7. form表单中的 action=./?> 是什么意思

    ./代表当前目录,?代表查询字符串为空 action="" //一般可以为空的,这里的双引号都要有的,表示提单提交给自己(也就是当前页处理)action="a.php&q ...

  8. html5css3杂记

    最新版本号的safari.chrome.firefox以及opera支持某些html5特性.ie9将支持某些html5特性. html5提供了展现视频的标准<video>支持ogg及mpe ...

  9. 你真的了解mysql的varchar字段的长度有多少吗?

    今天在设计系统字段的时候, 发现自己对varchar还不够了解.我设了一个字段.类型为VARCHER,然后我就往里面测试性了写了东西.发现没有多少就满了.我觉得奇怪,5.5版本以上的MYSQL不是有6 ...

  10. WorkFlow介绍及用法

    WorkFlow介绍及用法 说起workflow大家肯定都不陌生,这里简单介绍一下salesforce中什么情况下使用workflow. 当你分配许多任务,定期发送电子邮件,记录修改时,可以通过自动配 ...