题意:给出大写字母组成的模式串,再给出一个字串匹配,问每个模式串在母串中出现的次数,母串为可见字符ASCII。
注意字典树开next的大小,没看清题MLE好几次。。
#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int kind = 28; int num[1005]; char str[2000002],key[1002][55]; struct node { node *fail; node *next[kind]; int id; int count;//记录当前前缀是完整单词出现的个数 node() { fail = NULL; count = 0; memset(next,NULL,sizeof(next)); id=-1; } }; void insert(char *str,node *root,int m) { 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++; p->id=m; } //寻找失败指针 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]) { if(str[i]>='A'&&str[i]<='Z') index = str[i]-'A'; else index=27; 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->id!=-1)//寻找到当前位置为止是否出现病毒关键字 { //if(temp->count!=0) //cnt+=temp->count; num[temp->id]++; //temp->count=-1; temp=temp->fail; } i++; } return cnt; } int Delete(node *T) { if(T==NULL) return 0; for(int i=0; i<26; i++) if(T->next[i]!=NULL) Delete(T->next[i]); delete T; return 0; } int main() { int n; while(~scanf("%d\n",&n)) { node root; for(int i=0; i<n; i++) { gets(key[i]); insert(key[i],&root,i); } memset(num,0,sizeof(num)); build_ac_automation(&root); gets(str); query(&root); for(int i=0; i<n; i++) if(num[i]) printf("%s: %d\n",key[i],num[i]); Delete(&root); } return 0; }