您的位置:首页 > 其它

AC自动机以及KMP模板

2017-07-31 19:39 351 查看


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++;
}

//用队列实现fail
void 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;
}
else
break;
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ACM