ac自动机说起来很复杂,其实和kmp是一样的思路,都是寻找相同前后缀,减少跳的次数。只要理解了kmp是怎么求next数组的,ac自动机bfs甚至比knp还好写。

这里大致说一下kmp求next数组的方法吧,假设现在要求第c个字符的next值(假设这个c很大,这样画图出来比较清晰方便理解),因为遍历过程中我们已经知道了第c-1个字符的next为x(假设比c小很多),即next[c-1] = x。那就代表我们知道了a[1]—a[x]这一段和a[c-1-x]—a[c-1]这一段是相等的对吧。

那么现在有两种情况

一。a[x+1] 和 a[c]相等,那么显然变成了a[1]—a[x+1] 这一段和a[c-1-x]—a[c]这一段相等,即c位置的相同前后缀长度比c-1多了1,就是next[c-1]+1;

即原来是:

1——————————x      == c-1-x ————————————————c-1  ① 由于a[x+1] == a[c],变成了

1——————————x+1  == c-1-x——————————————————c

二。如果不相等,那么我们在1——x这一段下功夫,假设next[x] = y,即1——y == x-y——x这两段相等,注意根据①式,x-y——x == c-1-y——c-1,画个图就很清楚了,所以如果a[y+1] == a[c],那么相同前后缀长度就是y+1了。

即因为

1——————————x   ==    c-1-x————————————————c-1  

1——y    ==   x-y———x   ==    c-1-x——c-1-x+y     ==       c-1-y————c-1   由于a[y+1] == a[c],变成了

1——y+1             ==          c-1-y——————c

那如果a[y+1] 与a[c]还是不相等怎么办?其实细心的话应该发现这是一个递归过程了——只要再找next[y],循环上面的过程就可以了,想明白这个过程再去看求next数组的代码就很容易理解了。

最后还是上这道题代码:

 #include <iostream>
#include <string.h>
#include <cstdio>
#include <queue>
#include <set>
#include <stack>
#include <math.h>
#include <string>
#include <algorithm> #define SIGMA_SIZE 26
#define pii pair<int,int>
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) (x&-x)
#define fode(i, a, b) for(int i=a; i>=b; i--)
#define foe(i, a, b) for(int i=a; i<=b; i++)
#define fod(i, a, b) for(int i=a; i>b; i--)
#define fo(i, a, b) for(int i=a; i<b; i++)
//#pragma warning ( disable : 4996 ) using namespace std;
typedef long long LL;
inline LL LMax(LL a, LL b) { return a>b ? a : b; }
inline LL LMin(LL a, LL b) { return a>b ? b : a; }
inline LL lgcd(LL a, LL b) { return b == ? a : lgcd(b, a%b); }
inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; } //a*b = gcd*lcm
inline int Max(int a, int b) { return a>b ? a : b; }
inline int Min(int a, int b) { return a>b ? b : a; }
inline int gcd(int a, int b) { return b == ? a : gcd(b, a%b); }
inline int lcm(int a, int b) { return a / gcd(a, b)*b; } //a*b = gcd*lcm
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL lmod = 1e9+;
const int mod = ;
const double eps = 1e-;
const int inf = 0x3f3f3f3f;
const int maxk = 1e5+;
const int maxm = *;
const int maxn = 5e5+; struct node {
node *fail, *s[];
int w;
node() {} void init() {
fail = NULL;
fo(i, , ) s[i] = NULL;
w = ;
}
}*head; int n, ans;
char str[];
queue<node*> q; node* getfail(node* p, int x)
{
if (p->s[x] != NULL) return p->s[x];
else {
if (p == head) return head;
else return getfail(p->fail, x);
}
} void build()
{
node* root = head;
node* tmp; int len = strlen(str);
for ( int j = ; j < len; j++ )
{
int k = str[j]-'a';
if (root->s[k] == NULL) {
tmp = new node; tmp->init();
tmp->fail = head;
root->s[k] = tmp;
} root = root->s[k];
//标记单词结尾
if (j == len-) root->w++;
}
} void build_ac()
{
node* r;
while(!q.empty()) q.pop();
q.push(head);
while(!q.empty())
{
r = q.front(); q.pop();
fo(j, , )
{
if (r->s[j] != NULL) {
q.push(r->s[j]);
if (r == head) r->s[j]->fail = head;
else r->s[j]->fail = getfail(r->fail, j);
}
}
}
return;
} void solve()
{
int len = strlen(str);
node *tmp, *r = head;
fo(j, , len)
{
int k = str[j]-'a';
//找到前缀
while( r->s[k]==NULL && r != head ) r = r->fail;
//自动机向下匹配
//如果可以匹配,则进入下一节点,否则返回头节点
r = (r->s[k]==NULL) ? head : r->s[k];
tmp = r; //如果单词a出现,则他的前缀也全部出现过
while(tmp != head) {
ans += tmp->w;
tmp->w = ;
tmp = tmp->fail;
}
}
return;
} void init()
{
cin >> n; ans = ;
head = new node, head->init();
foe(i, , n)
scanf("%s", str), build(); build_ac();
scanf("%s", str);
} int main()
{ #ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
#endif int t; cin >> t;
while(t--)
{
init();
solve();
printf("%d\n", ans);
} return ;
}

Keywords Search HDU2222 AC自动机模板题的更多相关文章

  1. HDU-2222 Keywords Search(AC自动机--模板题)

    题目大意:统计一共出现了多少次模板串. 题目分析:AC自动机的模板题.不过这题有坑,相同的模板串不能只算一次. 代码如下: # include<iostream> # include< ...

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

    http://acm.hdu.edu.cn/showproblem.php?pid=2222 题意:给出多个单词,最后再给出一个模式串,求在该模式串中包含了多少个单词. 思路: AC自动机的模板题. ...

  3. hdu_2222: Keywords Search(AC自动机模板题)

    题目链接 统计一段字符串中有多少个模板串在里面出现过 #include<bits/stdc++.h> using namespace std; ; struct Trie { ]; int ...

  4. HDU2222 Keywords Search(AC自动机模板)

    AC自动机是一种多模式匹配的算法.大概过程如下: 首先所有模式串构造一棵Trie树,Trie树上的每个非根结点都代表一个从根出发到该点路径的字符串. 然后每个结点都计算出其fail指针的值,这个fai ...

  5. HDU 2222 Keywords Search(AC自动机模版题)

    Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others ...

  6. HDU 2222 Keywords Search 【AC自动机模板】

    询问有多少个模式串出现在了文本串里面.将模式串插入Trie树中,然后跑一边AC自动机统计一下就哦了. 献上一份模板. #include <cstdio> #include <cstr ...

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

    http://acm.hdu.edu.cn/showproblem.php?pid=2222 KMP是单模式串匹配的算法,而AC自动机是用于多模式串匹配的算法.主要由Trie和KMP的思想构成. 题意 ...

  8. HDU 2222 AC自动机模板题

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

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

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

随机推荐

  1. NX二次开发-UFUN点构造器UF_UI_point_construct

    #include <uf.h> #include <uf_ui.h> UF_initialize(); //点构造器 char sCue[] = "点构造器" ...

  2. NX二次开发-如何在类外面定义一个结构体

    #include <uf.h> #include <uf_obj.h> #include <uf_part.h> using namespace NXOpen; u ...

  3. map和unordered_map使用小结

    map和unordered_map unordered_map简介: #include <cstdio> #include <iostream> #include <un ...

  4. java基础编程题(2)

    1.给定一个二叉树,找出其最大深度. 注:二叉树的深度为根节点到最远叶子节点的最长路径上的节点数. /** * Definition for a binary tree node. * public ...

  5. MySQL初步理解,简易单表增删改查

    什么是数据库? 存储数据的仓库,本质是一个文件系统,封装了算法和文件之前数据的存储模式 阶段1:集合 数组 变量 缺点:数据存储在内存中,不能实现数据的持久化存储 阶段2:IO流 结合文件 .txt ...

  6. neo4j 基本概念和Cypher语句总结

    下面是一个介绍基本概念的例子,参考链接Graph database concepts: (1) Nodes(节点) 图谱的基本单位主要是节点和关系,他们都可以包含属性,一个节点就是一行数据,一个关系也 ...

  7. 免费的高分辨率图库——re:splashed 可用做网页背景、设计或桌面壁纸

    想找高清图片用作网站背景.设计或桌面壁纸?可以去re:splashed看看.re:splashed 是一个提供免费高分辨率HD图片的网站,有多种分类标签,查找很方便,无需注册和登陆便可下载. 网站名称 ...

  8. Qt学习笔记----基础知识

    一.qt的本质 qt的本质是c++的图形界面类库,本身是mvc结构.qt能火最大程度 归功于它跨平台的特性,一次编码,多次编译应用. 注意:qt由于历史原因,经历了奇趣.诺基亚.digit公司,导致q ...

  9. java oop遍历List和Map的几种方法

    一.list的遍历 import java.util.*; public class ListTest { public static void main(String[] args) { List& ...

  10. github代码推送

    git init // 初始化版本库 git add . // 添加文件到版本库(只是添加到缓存区),.代表添加文件夹下所有文件 git commit -m "first commit&qu ...