HDU 3065 病毒侵袭持续中(AC自动机)
题目链接:HDU 3065
AC自动机第二题~
模板几乎没有改动,只是模式字符串中出现了字母以外的字符需要处理一下,还有需要将计数的标记取消。
源代码
#include <iostream> #include <cstring> #include <cstdio> using namespace std; const int kind = 27; struct node{ node *next[kind]; int count ; node* fail; node(){ count = 0; fail = NULL; memset(next,0,sizeof(next)); } }*q[5000000]; int ans[1111]; node *root; int head,tail; char word[1010][55]; char str[2000010]; void insert(char *s,int k){ //构建trie int len = strlen(s); node *p = root; for(int i=0;i<len;i++){ int index = s[i]-'A'; if(!p->next[index]) p->next[index] = new node; p=p->next[index]; } p->count = k; } void build_ac_automation(){ //初始化fail指针 q[tail++] = root; while(head<tail){ node *p = q[head++]; node *tmp = NULL; for(int i=0;i<kind;i++){ if(p->next[i] != NULL){ if(p == root)//首元素必须指根 p->next[i]->fail = root; else{ tmp = p->fail; //失败指针(跳转指针) while(tmp != NULL){ if(tmp->next[i] != NULL){//找到匹配 p->next[i]->fail = tmp->next[i]; break; } //如果没找到,则继续向上一个失败指针找 tmp = tmp->fail; } if(tmp == NULL) //为空 则从头匹配 p->next[i]->fail = root; } q[tail++] = p->next[i];//下一层入队 } } } } void query(){ int len = strlen(str); node *p = root; int cnt = 0; int index; for(int i=0;i<len;i++){ if(str[i]<'A' || str[i] > 'Z') index = 26; else index = str[i]-'A'; while(p->next[index] == NULL && p!=root) p = p->fail; p = p->next[index]; if(p == NULL) p = root; node *tmp = p;//tmp 动 , p不动。 while(tmp != root && tmp->count != 0){ ans[tmp->count]++; tmp = tmp ->fail; } } } void clear(node *root){ if(!root) return ; else{ for(int i=0;i<kind;i++) clear(root->next[i]); } delete(root); } int main(){ int n; while(scanf("%d",&n)!=EOF){ memset(ans,0,sizeof(ans)); root = new node; getchar(); for(int i=0;i<n;i++){ gets(word[i]); insert(word[i],i+1); } gets(str); head = tail = 0; build_ac_automation(); query(); int m; for(int i=1;i<=n;i++){ if(ans[i]){ printf("%s: %d\n",word[i-1],ans[i]); } } clear(root); } return 0; }