这是对于AC自动机代码的理解,代码是网上找的大佬的,纯属记录。
链接如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string.h>
#include <string>
using namespace std;
const int maxn = 1e7 + 5;
const int MAX = 10000000;
int cnt;struct node {
node *next[26];//子节点(最多26个)
node *fail;//指针指向
int sum;//记录有多少种路径可以到达
};
node *root;
char key[70];
node *q[MAX];
int head, tail;
node *newnode;
char pattern[maxn];
int N;
void Insert(char *s)//向字典树添加节点(建树)
{
node *p = root;
for (int i = 0; s[i]; i++)//当单词还没有到末尾时
{
int x = s[i] - 'a';
if (p->next[x] == NULL)//如果还没有添加过这个字母
{
newnode = new node;
for (int j = 0; j<26; j++) newnode->next[j] = 0;//又一轮初始化,将指针归0,将下一个节点归0,将sum归0
newnode->sum = 0; newnode->fail = 0;
p->next[x] = newnode;//将新开辟的空间赋给p的下一个节点,边是x,将点移到下一个节点处
}
p = p->next[x];//如果添加过这个字母,将点移到下一个节点处
}
p->sum++;//此单词的数量加1//同时也表示这个节点是一个单词的末尾
}
void build_fail_pointer()//建立如同KMP的指针指向//基于队列BFS进行实现
{
head = 0;
tail = 1;
q[head] = root;//先将指针指向root节点
node *p;
node *temp;
while (head < tail)
{
temp = q[head++];
for (int i = 0; i <= 25; i++)
{
if (temp->next[i])//如果下一个节点存在
{
if (temp == root)//如果该节点是根节点
{
temp->next[i]->fail = root;//将指针置于根节点
}
else
{
p = temp->fail;//如果该节点不是根节点
while (p)//如果指针已经有指向了//不停的跑循环,直到指针所指向的点下没有节点或者下一个节点存在时
{
if (p->next[i])//如果指针指向的那个节点的下一个节点存在
{
temp->next[i]->fail = p->next[i];//该节点的下一个节点的指针指向原来指向的节点的下一个节点???如何判断所指向的那串东西是后缀呢???
break;
}
p = p->fail;//将指针放到指向的节点处
}
if (p == NULL) temp->next[i]->fail = root;//如果指针还没有指向,那么将指针指向根节点
}
q[tail++] = temp->next[i];//将指针放到下一层节点处
}
}
}
}
void ac_automation(char *ch)//利用求得的fail指针进行匹配
{
node *p = root;//先将指针指向根节点
int len = strlen(ch);
for (int i = 0; i < len; i++)
{
int x = ch[i] - 'a';
while (!p->next[x] && p != root) p = p->fail;//当p存在下一个节点时,p指到p的下一个匹配点处
p = p->next[x];//指到x对应那条边连接的节点处
if (!p) p = root;//如果p是空的,那么指到根节点处
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 = new node;// (struct node *)malloc(sizeof(struct node));
for (int j = 0; j<26; j++) root->next[j] = 0;//刚开始时的所有节点初始化为0
root->fail = 0;//刚开始时的所有指针指向初始化为0
root->sum = 0;//个数初始化为0
scanf("%d", &N);
for (int i = 1; i <= N; i++)
{
cin>>key;
Insert(key);
}
cin>>pattern;
cnt = 0;
build_fail_pointer();
ac_automation(pattern);
printf("%d\n", cnt);
}
return 0;
}