AC自动机的算法来自贝尔实验室,它是一种解决多模式串匹配问题的算法。
如:给出n个单词T,再给出一段包含m个字符串的文章,问有多少个单词在文章里出现?
它结合了KMP算法和Trie字典树算法。所以学习AC自动机前要先学习KMP和Trie。
提供一些学习资料:https://www.bilibili.com/video/av2975983/?p=37【KMP算法学习视频】
Trid字典树模板:https://blog.csdn.net/waterboy_cj/article/details/81357881
Trid字典树运用:https://blog.csdn.net/waterboy_cj/article/details/81358819
AC自动机过程详解:https://www.cnblogs.com/cmmdc/p/7337611.html【讲解很到位,代码emmmm】
附AC自动机实现完整代码(按程序提示输入即可):
#include <bits/stdc++.h>
using namespace std;
int cnt;
struct acnode
{
int sum;
acnode* next[26];
acnode* fail;
acnode()
{
for (int i = 0; i<26; i++)
next[i] = NULL;
fail = NULL;
sum = 0;
}
}*root;
acnode* newnode()
{
acnode *p = new acnode;
for (int i = 0; i<26; i++)
p->next[i] = NULL;
p->fail = NULL;
p->sum = 0;
return p;
}
//插入函数
void Insert(char *s)
{
acnode *p = root;
for (int i = 0; s[i]; i++)
{
int x = s[i] - 'a';
if (p->next[x] == NULL)
{
acnode *nn = newnode();
for (int j = 0; j<26; j++)
nn->next[j] = NULL;
nn->sum = 0;
nn->fail = NULL;
p->next[x] = nn;
}
p = p->next[x];
}
p->sum++;
}
//获取fail指针
void getfail()
{
queue<acnode*> q;
for (int i = 0; i < 26; i++)
{
if (root->next[i] != NULL)
{
root->next[i]->fail = root;
q.push(root->next[i]);
}
}
while (!q.empty())
{
acnode* tem = q.front();
q.pop();
for (int i = 0; i<26; i++)
{
if (tem->next[i] != NULL)
{
acnode *p;
if (tem == root)
{
tem->next[i]->fail = root;
}
else
{
p = tem->fail;
while (p != NULL)
{
if (p->next[i] != NULL)
{
tem->next[i]->fail = p->next[i];
break;
}
p = p->fail;
}
if (p == NULL)
tem->next[i]->fail = root;
}
q.push(tem->next[i]);
}
}
}
}
//匹配函数
void ac_automation(char *ch)
{
acnode *p = root;
int len = strlen(ch);
for (int i = 0; i < len; i++)
{
int x = ch[i] - 'a';
while (p->next[x] == NULL && p != root)//匹配失败,那么找fail指针。
p = p->fail;
p = p->next[x];
if (!p)
p = root;
acnode *temp = p;
while (temp != root)
{
if (temp->sum >= 0)//此时匹配成功
{
cnt += temp->sum;
temp->sum = -1;
}
else break;
temp = temp->fail;
}
}
}
int main()
{
cnt = 0;
int n;
cout << "请输入要匹配的子串数:" << endl;
cin >> n;
char c[101];
root = newnode();
for (int i = 0; i < n; i++)
{
cout << "输入第 " << i + 1 << " 个子串:"<< endl;
scanf("%s", c);
Insert(c);
}
getfail();
int m;
cout << "请输入匹配的主串数:" << endl;
cin >> m;
for (int i = 0; i<m; i++)
{
cout << "输入第 " << i + 1 << " 个主串:" << endl;
scanf("%s", c);
ac_automation(c);
}
cout << cnt << endl;
return 0;
}