AC自动机以及KMP模板

来源:互联网 发布:怎么购买备案域名 编辑:程序博客网 时间:2024/06/05 01:02

AC自动机

 
Aho-Corasick automaton,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法。
要学会AC自动机,我们必须知道什么是Trie,也就是字典树。Trie树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。
应用
一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。
要搞懂AC自动机,先得有模式树(字典树)Trie和KMP模式匹配算法的基础知识。AC自动机算法分为3步:构造一棵Trie树,构造失败指针和模式匹配过程。

//AC自动机模板#include <bits/stdc++.h>using namespace std;const int maxn = 1e7 + 5;const int MAX = 10000000;struct node{node *next[26];node *fail;int sum;};node *root;node *q[MAX];          //队列char partner[maxn];char s[105];int head, tail;int cnt;//建立字典树void Insert(char *s){node *p = root;for(int i=0; s[i]; i++){int x = s[i] - 'a';if(p->next[x]==NULL){node *temp = (node *)malloc(sizeof(node));for(int j=0; j<26; j++)temp->next[j] = 0;temp->sum = 0;temp->fail = 0;p->next[x] = temp;}p = p->next[x];}p->sum++;}//用队列实现failvoid build_fail_pointer(){head = 0;tail = 1;q[head] = root;while(head < tail){node *temp = q[head++];for(int i=0; i<26; i++){if(temp->next[i]){if(temp == root){temp->next[i]->fail = root;}else{node *r = temp->fail;while(r){if(r->next[i]){temp->next[i]->fail = r->next[i];break;}r = r->fail;}if(r==NULL)temp->next[i]->fail = root;}q[tail++] = temp->next[i];}}}}//匹配单词void ac_automation(char *partner){node *p = root;int len = strlen(partner);for(int i=0; i<len; i++){int x = partner[i]-'a';while(!p->next[x] && p!=root)p = p->fail;p = p->next[x];if(!p)p = root;node *temp = p;while(temp != root){if(temp->sum >= 0){cnt += temp->sum;temp->sum = -1;}elsebreak;temp = temp->fail;}}}int main(){int T;scanf("%d", &T);while(T--){root = (node *)malloc(sizeof(node));for(int i=0; i<26; i++)root->next[i] = 0;root->sum = 0;root->fail = 0;int n;scanf("%d", &n);getchar();for(int i=1; i<=n; i++){gets(s);Insert(s);}gets(partner);cnt = 0;build_fail_pointer();ac_automation(partner);printf("%d\n", cnt);}return 0;}


//KMP模板//T是模式串void getNext(char *T){    int j, k, tlen = strlen(T);    j = 0; k = -1; next[0] = -1;    while(j < tlen)        if(k == -1 || T[j] == T[k])            next[++j] = ++k;        else            k = next[k];}//返回模式串T在主串S中首次出现的位置//返回的位置是从0开始的。int KMP_Index(char *T, char *S){    int i = 0, j = 0;    getNext(T);    int slen = strlen(S);    int tlen = strlen(T);    while(i < slen && j < tlen)    {        if(j == -1 || S[i] == T[j])        {            i++; j++;        }        else            j = next[j];    }    if(j == tlen)        return i - tlen;    else        return -1;}


AC自动机模板题目:HDU 2222

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2222