AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一。要搞懂AC自动机,先得有模式树(字典树)Trie、广度优先策略和KMP模式匹配算法的基础知识。
关于AC自动机
建立Aho-Corasick automation算法需要三步:
- 建立模式串的Trie
- 给Trie添加失配路径
- 根据AC自动机,搜索待处理的文本
这里以航电OJ上的一道题hdu 2222 KeywordsSearch为例子。
1 2 3
| 给定5个单词:say she shr he her 一个字符串:yasherhs 问一共有多少单词在这个字符串中出现。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
| #include <stdio.h> #include <stdlib.h> #include <string.h> struct Node { int cnt; Node *fail; Node *next[26]; }*queue[500005]; char s[1000005]; char keyword[55]; Node *root; void Init(Node *root) { root->cnt=0; root->fail=NULL; for(int i=0;i<26;i++) root->next[i]=NULL; } void Build_trie(char *keyword) { Node *p,*q; int i,v; int len=strlen(keyword); for(i=0,p=root;i<len;i++) { v=keyword[i]-'a'; if(p->next[v]==NULL) { q=(struct Node *)malloc(sizeof(Node)); Init(q); p->next[v]=q; } p=p->next[v]; } p->cnt++; } void Build_AC_automation(Node *root) { int head=0,tail=0; queue[head++]=root; while(head!=tail) { Node *p=NULL; Node *temp=queue[tail++]; for(int i=0;i<26;i++) { if(temp->next[i]!=NULL) { if(temp==root) temp->next[i]->fail=root; else { p=temp->fail; while(p!=NULL) { if(p->next[i]!=NULL) { temp->next[i]->fail=p->next[i]; break; } p=p->fail; } if(p==NULL) temp->next[i]->fail=root; } queue[head++]=temp->next[i]; } } } } int query(Node *root) { int i,v,count=0; Node *p=root; int len=strlen(s); for(i=0;i<len;i++) { v=s[i]-'a'; while(p->next[v]==NULL && p!=root) p=p->fail; p=p->next[v]; if(p==NULL) p=root; Node *temp=p; while(temp!=root) { if(temp->cnt>=0) { count+=temp->cnt; temp->cnt=-1; } else break; temp=temp->fail; } } return count; } int main() { int T,n; scanf("%d",&T); while(T--) { root=(struct Node *)malloc(sizeof(Node)); Init(root); scanf("%d",&n); for(int i=0;i<n;i++) { scanf("\n%s",keyword); Build_trie(keyword); } Build_AC_automation(root); scanf("\n%s",s); printf("%d\n",query(root)); } return 0; }
|