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巨的博客,太简洁了:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<queue>
 4 using namespace std;
 5 int root=1,tn,ch[510000][26],cnt[510000],fail[510000];
 6 void insert(char *s){
 7     int x=1;
 8     for(int i=0; s[i]; ++i){
 9         int y=s[i]-‘a‘;
10         if(ch[x][y]==0) ch[x][y]=++tn;
11         x=ch[x][y];
12     }
13     ++cnt[x];
14 }
15 void init(){
16     queue<int> que;
17     for(int i=0; i<26; ++i){
18         if(ch[root][i]==0) ch[root][i]=1;
19         else que.push(ch[root][i]),fail[ch[root][i]]=root;
20     }
21     while(!que.empty()){
22         int now=que.front(); que.pop();
23         for(int i=0;i<26;++i){
24             if(ch[now][i]==0) ch[now][i]=ch[fail[now]][i];
25             else que.push(ch[now][i]),fail[ch[now][i]]=ch[fail[now]][i];
26         }
27     }
28 }
29 int query(char *s){
30     int now=root,res=0;
31     for(int i=0; s[i]; ++i){
32         int tmp=now=ch[now][s[i]-‘a‘];
33         while(tmp!=1){
34             if(cnt[tmp]>=0){
35                 res+=cnt[tmp];
36                 cnt[tmp]=-1;
37             }else break;
38             tmp=fail[tmp];
39         }
40     }
41     return res;
42 }
43 char S[1100000],T[55];
44 int main(){
45     int t,n;
46     scanf("%d",&t);
47     while(t--){
48         tn=1;
49         memset(ch,0,sizeof(ch));
50         memset(cnt,0,sizeof(cnt));
51         scanf("%d",&n);
52         while(n--){
53             scanf("%s",T);
54             insert(T);
55         }
56         init();
57         scanf("%s",S);
58         printf("%d\n",query(S));
59     }
60     return 0;
61 }

另外之前学的指针版本的,指针版本跑得更快:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<queue>
 4 using namespace std;
 5 typedef struct Node *pNode;
 6 struct Node{
 7     int cnt;
 8     pNode fail,nxt[26];
 9     Node(){
10         cnt=0; fail=NULL;
11         for(int i=0;i<26;++i) nxt[i]=NULL;
12     }
13 };
14 pNode root;
15 char S[1000100];
16 void insert(char *s){
17     pNode p=root;
18     for(int i=0;s[i];++i){
19         int index=s[i]-‘a‘;
20         if(p->nxt[index]==NULL){
21             p->nxt[index]=new Node;
22         }
23         p=p->nxt[index];
24     }
25     ++p->cnt;
26 }
27 void init(){
28     queue<pNode> que;
29     que.push(root);
30     while(que.size()){
31         pNode y=que.front(); que.pop();
32         for(int i=0;i<26;++i){
33             if(y->nxt[i]==NULL) continue;
34             if(y==root){
35                 y->nxt[i]->fail=root;
36                 que.push(y->nxt[i]);
37                 continue;
38             }
39             pNode x=y->fail;
40             while(x&&x->nxt[i]==NULL) x=x->fail;
41             if(x==NULL) y->nxt[i]->fail=root;
42             else y->nxt[i]->fail=x->nxt[i];
43             que.push(y->nxt[i]);
44         }
45     }
46 }
47 int query(){
48     int res=0;
49     pNode x=root;
50     for(int i=0;S[i];++i){
51         int index=S[i]-‘a‘;
52         while(x->nxt[index]==NULL&&x!=root) x=x->fail;
53         x=x->nxt[index];
54         if(x==NULL) x=root;
55         pNode y=x;
56         while(y!=root){
57             if(y->cnt>=0){
58                 res+=y->cnt;
59                 y->cnt=-1;
60             }else break;
61             y=y->fail;
62         }
63     }
64     return res;
65 }
66 int main(){
67     int t,n;
68     char s[55];
69     scanf("%d",&t);
70     while(t--){
71         root=new Node;
72         scanf("%d",&n);
73         for(int i=0;i<n;++i){
74             scanf("%s",s);
75             insert(s);
76         }
77         scanf("%s",S);
78         init();
79         printf("%d\n",query());
80     }
81     return 0;
82 } 
时间: 2024-10-20 06:33:33

HDU2222 Keywords Search(AC自动机)的相关文章

hdu2222 Keywords Search ac自动机

地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=2222 题目: Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 56558    Accepted Submission(s): 18493 Problem Description In the mo

hdu2222 Keywords Search &amp; AC自动机学习小结

传送门:http://http://acm.hdu.edu.cn/showproblem.php?pid=2222 思路:AC自动机入门题,直接上AC自动机即可. 对于构建AC自动机,我们要做的只有三件事: 1)构建字典树 2)构建失败指针 3)构建trie图(这道题好像不做这一步也能A...但是这一步不做是会被卡成O(n^2)的...) 1)第一步还是比较好理解的 根是虚根,边代表字母,那么根到终止节点的路径就是一个字符串,这样对于前缀相同的字符串我们就可以省下存公共前缀的空间. 加入一个模式

HDU 2222 Keywords Search AC自动机入门题

单词统计的题目,给出一些单词,统计有多少单词在一个文本中出现,最经典的入门题了. AC自动机的基础: 1 Trie, 以这个数据结构为基础的,不过增加一个fail指针和构造fail的函数 2 KMP,不是直接运用KMP,而是需要KMP的思想,KMP思想都没有的话,理解这个算法会更加吃力的. 注意本题的单词会有重复出现的,一个单词只能统计一次. 搜索了一下网上的题解,发现好多代码都是一大抄的啊,⊙﹏⊙b汗. 本博客的乃是原创代码,代码风格也是差不多固定的,转载请注明出处:http://blog.c

[hdu2222] [AC自动机模板] Keywords Search [AC自动机]

AC自动机模板,注意!ch,Fail,lab数组的大小不是n而是节点个数,需要认真计算! 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 #include <ctime> 7 #include <cstdlib> 8 #include <queue>

HDU 2222 Keywords Search AC自动机

Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 67122    Accepted Submission(s): 22584 Problem Description In the modern time, Search engine came into the life of everybody lik

hdu 2222 Keywords Search(ac自动机入门题)

1 /************************************************************ 2 题目: Keywords Search(hdu 2222) 3 链接: http://acm.hdu.edu.cn/showproblem.php?pid=2222 4 算法: ac自动机 5 算法思想: 多个字符串匹配,也就是相当于多个kmp 6 ***********************************************************

HDU 2222 Keywords Search (AC自动机入门 模板)

AC自动机入门 Aho-Corasick automaton,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一.学习AC自动机之前得先有Trie树和KMP模式匹配算法的基础. AC自动机算法分为3步:1.构造一棵tire树  2.构造失败指针  3.进行模式匹配 AC自动机的优化:Trie图 Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other

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

Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 67950    Accepted Submission(s): 22882 Problem Description In the modern time, Search engine came into the life of everybody lik

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

多模匹配 题目大意:给定很多个字串A,B,C,D,E....,然后再给你目标串str字串,看目标串中出现多少个给定的字串. 经典AC自动机模板题,不多说. 1 #include <iostream> 2 #include <algorithm> 3 #include <functional> 4 #include <string.h> 5 #define MAX 26 6 7 using namespace std; 8 9 struct node 10 {

hdoj 2222 Keywords Search(AC自动机)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2222 思路分析:该问题为多模式匹配问题,使用AC自动机解决:需要注意的问题是如何统计该待查询的字符串包含的关键字: 假设待查找的字符串为str[0..n],则str[i…j]可能为某一个关键字:假设当前正在匹配字符str[k],则以str[i..k]为关键字的所有可能 可能的关键字的最后一个字符为str[k],使用fail指针进行跳转并判断以str[k]结尾的该结点是否为关键字最后一个结点,重复进行