这里找到了两篇很nice的Trie树(作者Hackbuteer1)以及AC自动机(作者niushuai666)入门详解。博主写的可以说是非常用心了,一看就懂。
题意:给出N(<=10000)个单词(长度<=50)组成的字典。求串T(长度<=1e6)中出现了字典中的多少个单词。
题解:AC自动机裸题。所谓AC自动机就是Trie树加上了KMP的fail指针,而且是多模式的fail指针,意思就是说Trie图是有相同前缀的两个单词会有相同的一段root出发的路径,这个fail指针不再是KMP里某一个串的后缀和前缀相同并取最大,而是当前这个点得到的串的后缀和所有串中某个前缀相同且取最大。求这个fail就只要把KMP的过程改成广搜就行了,因为每个字符下一个状态可以是若干字符。。。每次把T中下一个字符考虑进来,通过fail指针转移到Trie图上的一个点上,然后统计root到这个点得到的串 的所有后缀的cnt(就是通过fail一点一点跳到根,把路径上的答案都统计起来。并把统计过的答案置为-1防止重复计数,同时fail跳到答案是-1的点表示这个点到根的答案已经统计过了,那么就提前停下来。)。
模板是我自己写的。。。可能比较丑。。。马上我会找一个好看的贴过来233
Code:
#include<bits/stdc++.h>
using namespace std;
const int MAX1 = 55;
const int MAX2 = 1000050;
char a[MAX1];
char b[MAX2];
struct ACAM {
int id;
int cnt;
ACAM* fail;
ACAM* nxt[26];
};
ACAM* root;
void ACAM_Clear(ACAM* root){
for (int i=0;i<=25;i++){
if (root->nxt[i]!=NULL){
ACAM_Clear(root->nxt[i]);
}
}
free(root);
};
ACAM* ACAM_Create(int id){
ACAM* node = (ACAM*)(malloc(sizeof(ACAM)));
node->cnt=0;
node->fail = NULL;
node->id =id;
memset(node->nxt,0,sizeof(node->nxt));
return node;
}
void ACAM_Insert(ACAM* root,char* word){
ACAM* node = root;
char* p = word;
while (*p){
int id = *p-'a';
if (node->nxt[id]==NULL){
node->nxt[id] = ACAM_Create(id);
}
node = node->nxt[id];
p++;
}
node->cnt++;
}
ACAM* que[MAX2*10];
void ACAM_Build(ACAM* root){
int l=0,r=0;
for (int i=0;i<=25;i++){
if (root->nxt[i]!=NULL){
root->nxt[i]->fail = root;
for (int j=0;j<=25;j++){
if (root->nxt[i]->nxt[j]!=NULL){
root->nxt[i]->nxt[j]->fail = root;
r++;
que[r] = root->nxt[i]->nxt[j];
}
}
}
}
while (l<r){
l++;
ACAM* q = que[l];
// printf("%d %c\n",l,q->id+'a');
while (q->fail!=root&&q->fail->nxt[q->id]==NULL){
q->fail = q->fail->fail;
}
if (q->fail->nxt[q->id]!=NULL){
q->fail = q->fail->nxt[q->id];
}
// printf("%d fial = %c\n",l,q->fail->id+'a');
for (int i=0;i<=25;i++){
if (q->nxt[i]!=NULL){
q->nxt[i]->fail = q->fail;
r++;
que[r] = q->nxt[i];
}
}
}
}
int ACAM_Search(ACAM* root,char*word){
int ans=0;
ACAM* node = root;
char* p = word;
while (*p){
// printf("%c\n",*p);
int id = *p-'a';
while (node->nxt[id]==NULL&&node!=root){
node=node->fail;
}
if (node->nxt[id]!=NULL){
node = node->nxt[id];
}
ACAM* temp = node;
while (temp!=root&&temp->cnt!=-1){
ans+=temp->cnt;
temp->cnt = -1;
temp=temp->fail;
}
p++;
}
return ans;
}
void init(){
ACAM_Clear(root);
root = ACAM_Create(-1);
}
void input(){
int n;
scanf("%d",&n);
while (n--){
scanf("%s",a);
ACAM_Insert(root,a);
}
}
void solve(){
ACAM_Build(root);
scanf("%s",b);
printf("%d\n",ACAM_Search(root,b));
}
int main(){
int t;
scanf("%d",&t);
root = ACAM_Create(-1);
while (t--){
init();
input();
solve();
}
return 0;
}