大致题意:
给出n个模式串(长度不超过50),和一个文本串(长度不超过1000000),求出有多少个模式串在这个文本串中出现过。
大致思路:
标准的AC自动机问题,主要是学习模版,理解自动机的匹配机制。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include <algorithm>
using namespace std;
const int inf=1<<28;
const int nMax=500;
const int mMax=500005;
class node{
public:
int id;
int vis; //前缀记录标志
node *next[26],*fail;
node(){
vis=0;
fail=NULL;
for(int i=0;i<26;i++)next[i]=NULL;
}
}*root,*que[mMax];
void insert(char *s){ //构造前缀树
int i;
node *r=root;
int l=strlen(s);
for(i=0;i<l;i++){
int loc=s[i]-'a';
if(r->next[loc]==NULL){
r->next[loc]=new node();
}
r=r->next[loc];
}
r->vis++;
}
void acAuto(){ //用bfs为每个节点设定fail指针
int i,head=0,tail=0;
node *p,*tmp;
root->fail=NULL;
que[tail++]=root;
while(head<tail){
tmp=que[head++];
for(i=0;i<26;i++){
if(tmp->next[i]==NULL)continue;
if(tmp==root){
tmp->next[i]->fail=root;
}
else {
for(p=tmp->fail;p!=NULL;p=p->fail){
if(p->next[i]!=NULL){
tmp->next[i]->fail=p->next[i];
break;
}
}
if(p==NULL){
tmp->next[i]->fail=root;
}
}
que[tail++]=tmp->next[i];
}
}
}
int search(char *msg){
int i,idx,ans=0;
node *p=root,*tmp;
for(i=0;msg[i];i++){
idx=msg[i]-'a';
while(p->next[idx]==NULL&&p!=root){
p=p->fail;
}
p=p->next[idx];
if(p==NULL)p=root;
for(tmp=p;tmp!=NULL&&tmp->vis!=-1;tmp=tmp->fail){
ans+=tmp->vis;
tmp->vis=-1;
}
}
return ans;
}
int main(){
int cas,n,i;
char str[52],text[1000002];
scanf("%d",&cas);
while(cas--){
scanf("%d",&n);
root=new node();
while(n--){
scanf("%s",str);
insert(str);
}
acAuto();
scanf("%s",text);
printf("%d\n",search(text));
}
return 0;
}
另附上静态tire树版本,可以省去不少生成新对象的时间(动态250ms,静态180)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include <algorithm>
using namespace std;
const int inf=1<<28;
const int nMax=500;
const int mMax=500005;
class node{
public:
int id;
int vis; //前缀记录标志
node *next[26],*fail;
// node(){
// vis=0;
// fail=NULL;
// for(int i=0;i<26;i++)next[i]=NULL;
// }
}*root,*que[mMax],num[5000000];
int x;
node *newnode(){
node * p = num + x++;
for(int i = 0; i <26; i++){
p->next[i] = NULL;
}
p->fail=NULL;
p->vis=0;
return p;
}
void insert(char *s){ //构造前缀树
int i;
node *r=root;
int l=strlen(s);
for(i=0;i<l;i++){
int loc=s[i]-'a';
if(r->next[loc]==NULL){
r->next[loc]=newnode();
}
r=r->next[loc];
}
r->vis++;
}
void acAuto(){ //用bfs为每个节点设定fail指针
int i,head=0,tail=0;
node *p,*tmp;
root->fail=NULL;
que[tail++]=root;
while(head<tail){
tmp=que[head++];
for(i=0;i<26;i++){
if(tmp->next[i]==NULL)continue;
if(tmp==root){
tmp->next[i]->fail=root;
}
else {
for(p=tmp->fail;p!=NULL;p=p->fail){
if(p->next[i]!=NULL){
tmp->next[i]->fail=p->next[i];
break;
}
}
if(p==NULL){
tmp->next[i]->fail=root;
}
}
que[tail++]=tmp->next[i];
}
}
}
int search(char *msg){
int i,idx,ans=0;
node *p=root,*tmp;
for(i=0;msg[i];i++){
idx=msg[i]-'a';
while(p->next[idx]==NULL&&p!=root){
p=p->fail;
}
p=p->next[idx];
if(p==NULL)p=root;
for(tmp=p;tmp!=NULL&&tmp->vis!=-1;tmp=tmp->fail){
ans+=tmp->vis;
tmp->vis=-1;
}
}
return ans;
}
int main(){
int cas,n,i;
char str[52],text[1000002];
scanf("%d",&cas);
while(cas--){
x=0;
scanf("%d",&n);
root=newnode();
while(n--){
scanf("%s",str);
insert(str);
}
acAuto();
scanf("%s",text);
printf("%d\n",search(text));
}
return 0;
}