AC自动机模板
每个节点只访问一次。
//子树节点是在插入时new的, //寻找失配指针中使用的队列是直接调用STL的 const int kind = 26; struct node { node *fail; node *next[kind]; int count;//记录当前前缀是完整单词出现的个数 node() { fail = NULL; count = 0; memset(next,NULL,sizeof(next)); } }; void insert(char *str,node *root) { node *p=root; int i=0,index; while(str[i]) { index = str[i]-'a'; if(p->next[index]==NULL) p->next[index]=new node(); p=p->next[index]; i++; } p->count++; } //寻找失败指针 void build_ac_automation(node *root) { int i; queue<node *>Q; root->fail = NULL; Q.push(root); while(!Q.empty()) { node *temp = Q.front();//q[head++];//取队首元素 Q.pop(); node *p = NULL; for(i=0; i<kind; i++) { if(temp->next[i]!=NULL)//寻找当前子树的失败指针 { p = temp->fail; while(p!=NULL) { if(p->next[i]!=NULL)//找到失败指针 { temp->next[i]->fail = p->next[i]; break; } p = p->fail; } if(p==NULL)//无法获取,当前子树的失败指针为根 temp->next[i]->fail = root; Q.push(temp->next[i]); } } } } //询问str中包含n个关键字中多少种即匹配 int query(node *root) { int i = 0,cnt = 0,index,len; len = strlen(str); node *p = root; while(str[i]) { index = str[i]-'a'; while(p->next[index]==NULL&&p!=root)//失配 p=p->fail; p=p->next[index]; if(p==NULL)//失配指针为根 p = root; node *temp = p; while(temp!=root&&temp->count!=-1)//寻找到当前位置为止是否出现病毒关键字 { //if(temp->count!=0) cnt+=temp->count; temp->count=-1; temp=temp->fail; } i++; } return cnt; }
无限次访问的模板
#include <iostream> #include <cstring> #include <cstdio> #include <queue> using namespace std; const int kind = 256; struct node { node *fail; node *next[kind]; int count; bool visit; node() { fail = NULL; count = 0; visit = false; memset(next,NULL,sizeof(next)); } }; node* query_temp_que[1111]; void insert(unsigned char *str,node *root,int slen) { node *p=root; int i,index; for (i=0;i<slen;i++) { index = (int)str[i]; if(p->next[index]==NULL) p->next[index]=new node(); p=p->next[index]; } p->count++; } //寻找失败指针 void build_ac_automation(node *root) { int i; queue<node *>Q; root->fail = NULL; Q.push(root); while(!Q.empty()) { node *temp=Q.front();//q[head++];//取队首元素 Q.pop(); node *p=NULL; for(i=0; i<kind; i++) { if(temp->next[i]!=NULL)//寻找当前子树的失败指针 { p=temp->fail; while(p!=NULL) { if(p->next[i]!=NULL)//找到失败指针 { temp->next[i]->fail=p->next[i]; break; } p=p->fail; } if(p==NULL)//无法获取,当前子树的失败指针为根 temp->next[i]->fail=root; Q.push(temp->next[i]); } } } } //询问str中包含n个关键字中多少种即匹配 int query(unsigned char *str,node *root,int slen) { int i,cnt = 0,index; int head,tail; head=tail=0; node *p = root; for (i=0;i<slen;i++) { index = (int)str[i]; while(p->next[index]==NULL&&p!=root) p=p->fail; p=p->next[index]; if(p==NULL) p = root; node *temp = p; while(temp!=root&&!temp->visit)//寻找到当前位置为止是否出现病毒关键字 { cnt+=temp->count; temp->visit=true; query_temp_que[tail++]=temp; temp=temp->fail; } } while (head<tail) { node* cur=query_temp_que[head++]; cur->visit=false; } return cnt; }