大致题意:
给出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; }