hdu 3065(AC自动机)
病毒侵袭持续中
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 19012 Accepted Submission(s): 6255
Problem Description
小t非常感谢大家帮忙解决了他的上一个问题。然而病毒侵袭持续中。在小t的不懈努力下,他发现了网路中的“万恶之源”。这是一个庞大的病毒网站,他有着好多好多的病毒,但是这个网站包含的病毒很奇怪,这些病毒的特征码很短,而且只包含“英文大写字符”。当然小t好想好想为民除害,但是小t从来不打没有准备的战争。知己知彼,百战不殆,小t首先要做的是知道这个病毒网站特征:包含多少不同的病毒,每种病毒出现了多少次。大家能再帮帮他吗?
Input
第一行,一个整数N(1<=N<=1000),表示病毒特征码的个数。
接下来N行,每行表示一个病毒特征码,特征码字符串长度在1—50之间,并且只包含“英文大写字符”。任意两个病毒特征码,不会完全相同。
在这之后一行,表示“万恶之源”网站源码,源码字符串长度在2000000之内。字符串中字符都是ASCII码可见字符(不包括回车)。
接下来N行,每行表示一个病毒特征码,特征码字符串长度在1—50之间,并且只包含“英文大写字符”。任意两个病毒特征码,不会完全相同。
在这之后一行,表示“万恶之源”网站源码,源码字符串长度在2000000之内。字符串中字符都是ASCII码可见字符(不包括回车)。
Output
按以下格式每行一个,输出每个病毒出现次数。未出现的病毒不需要输出。
病毒特征码: 出现次数
冒号后有一个空格,按病毒特征码的输入顺序进行输出。
病毒特征码: 出现次数
冒号后有一个空格,按病毒特征码的输入顺序进行输出。
Sample Input
3
AA
BB
CC
ooxxCC%dAAAoen....END
Sample Output
AA: 2
CC: 1
Hint
Hit: 题目描述中没有被提及的所有情况都应该进行考虑。比如两个病毒特征码可能有相互包含或者有重叠的特征码段。 计数策略也可一定程度上从Sample中推测。AC代码1:seg=26
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 Finish time:9.13.2018 3 Author:依言 4 Algorithm:AC_Auto 5 */ 6 #include<iostream> 7 #include<cstdio> 8 #include<map> 9 #include<queue> 10 #include<cstring> 11 using namespace std; 12 #define is_upper(x) (((x)>='A') && ((x)<='Z')) 13 const int son=26; 14 const int maxn=1000*50+50; 15 16 char str[1010][60]; 17 struct AC_Auto 18 { 19 int root,L; 20 int next[maxn][son]; 21 int fail[maxn]; 22 int id[maxn];//记录当前结束字符所表示字符串的编号 23 24 void Initial() 25 { 26 L=0; 27 root=L++; 28 memset(id,0,sizeof(id)); 29 memset(next,-1,sizeof(next)); 30 } 31 void Build_Trie(const char *s,const int num) 32 { 33 int now=root; 34 while(*s != '\0') 35 { 36 int index=*s-'A'; 37 if(next[now][index] == -1) 38 next[now][index]=L++; 39 now=next[now][index]; 40 s++; 41 } 42 id[now]=num; 43 } 44 void Build_Fail() 45 { 46 queue<int >myqueue; 47 fail[root]=root;//容易忘,谨记 48 for(int i=0;i < son;++i) 49 if(next[root][i] == -1) 50 next[root][i]=root; 51 else 52 { 53 fail[next[root][i]]=root; 54 myqueue.push(next[root][i]); 55 } 56 while(!myqueue.empty()) 57 { 58 int now=myqueue.front(); 59 myqueue.pop(); 60 for(int i=0;i < son;++i) 61 if(next[now][i] == -1) 62 next[now][i]=next[fail[now]][i]; 63 else 64 { 65 fail[next[now][i]]=next[fail[now]][i]; 66 myqueue.push(next[now][i]); 67 } 68 } 69 } 70 void Query(const char *s,const int n) 71 { 72 int now=root; 73 int num[1010]; 74 memset(num,0,sizeof(num)); 75 while(*s != '\0') 76 { 77 if(is_upper(*s))//判断当前字符知否为大写字母 78 { 79 int index=*s-'A'; 80 now=next[now][index]; 81 int temp=now; 82 while(temp != root) 83 { 84 num[id[temp]]++; 85 temp=fail[temp]; 86 } 87 } 88 else//如果不是相当于用一段新的字符串从新匹配,让now赋值为root 89 now=root; 90 s++; 91 } 92 for(int i=1;i <= n;++i) 93 if(num[i] != 0) 94 printf("%s: %d\n",str[i],num[i]); 95 } 96 }; 97 AC_Auto ac; 98 char buf[2000010]; 99 int main() 100 { 101 int N; 102 while(~scanf("%d",&N))//多组输入,一下午全wa在这儿了 103 { 104 ac.Initial(); 105 for(int i=1;i <= N;++i) 106 { 107 scanf("%s",str[i]); 108 ac.Build_Trie(str[i],i); 109 } 110 ac.Build_Fail(); 111 scanf("%s",buf); 112 ac.Query(buf,N); 113 } 114 }
AC代码2:seg=128
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 Finish time:9.13.2018 3 Author:依言 4 Algorithm:AC_Auto 5 */ 6 #include<iostream> 7 #include<queue> 8 #include<cstdio> 9 #include<cstring> 10 using namespace std; 11 const int seg=128; 12 const int maxn=1000*50+50; 13 14 int N; 15 char str[1010][60]; 16 struct ac_auto 17 { 18 int root,L; 19 int next[maxn][seg]; 20 int fail[maxn]; 21 int id[maxn]; 22 int New_Node() 23 { 24 for(int i=0;i < seg;++i) 25 next[L][i]=-1; 26 id[L]=-1; 27 return L++; 28 } 29 void Initial() 30 { 31 L=0; 32 root=New_Node(); 33 } 34 void Build_Trie(const char *s,const int val) 35 { 36 int now=root; 37 while(*s != '\0') 38 { 39 if(next[now][*s] == -1) 40 next[now][*s]=New_Node(); 41 now=next[now][*s]; 42 s++; 43 } 44 id[now]=val;//当前字符串的最后一个字符存储当前字符串的编号 45 } 46 void Build_Fail() 47 { 48 queue<int >myqueue; 49 fail[root]=root; 50 for(int i=0;i < seg;++i) 51 if(next[root][i] == -1) 52 next[root][i]=root; 53 else 54 { 55 fail[next[root][i]]=root; 56 myqueue.push(next[root][i]); 57 } 58 while(!myqueue.empty()) 59 { 60 int now=myqueue.front(); 61 myqueue.pop(); 62 for(int i=0;i < seg;++i) 63 if(next[now][i] == -1) 64 next[now][i]=next[fail[now]][i]; 65 else 66 { 67 fail[next[now][i]]=next[fail[now]][i]; 68 myqueue.push(next[now][i]); 69 } 70 } 71 } 72 void Query(const char *s) 73 { 74 int num[1010]; 75 memset(num,0,sizeof(num)); 76 int now=root; 77 while(*s != 0) 78 { 79 now=next[now][*s]; 80 int temp=now; 81 while(temp != root) 82 { 83 if(id[temp] != -1) 84 num[id[temp]]++; 85 temp=fail[temp]; 86 } 87 s++; 88 } 89 for(int i=1;i <= N;++i) 90 if(num[i]) 91 printf("%s: %d\n",str[i],num[i]); 92 } 93 }; 94 ac_auto ac; 95 char buf[2000010]; 96 97 int main() 98 { 99 while(~scanf("%d",&N))//多组输入,坑 100 { 101 ac.Initial(); 102 for(int i=1;i <= N;++i) 103 { 104 scanf("%s",str[i]); 105 ac.Build_Trie(str[i],i); 106 } 107 ac.Build_Fail(); 108 scanf("%s",buf); 109 ac.Query(buf); 110 } 111 }
AC代码3:链表
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 using namespace std; 6 #define is_upper(x) (((x)>='A')&&((x)<='Z')) 7 const int maxn=26; 8 9 struct Node 10 { 11 Node *next[maxn];//0~~25 分别对应 a~~z || A~~Z 12 Node *fail; 13 int id; 14 Node() 15 { 16 fail=NULL; 17 id=0;//初始化编号为0 18 memset(next,NULL,sizeof(next)); 19 } 20 }; 21 int N; 22 char str[1010][60]; 23 24 void Build_Tire(Node *root,const char *s,const int id) 25 { 26 Node *p=root; 27 while(*s != '\0') 28 { 29 if(p->next[*s-'A'] == NULL) 30 p->next[*s-'A']=new Node(); 31 p=p->next[*s-'A']; 32 s++; 33 } 34 p->id=id; 35 } 36 void Build_fail(Node *root) 37 { 38 queue<Node *>myqueue; 39 Node *p=root; 40 root->fail=NULL; 41 myqueue.push(root); 42 43 while(!myqueue.empty()) 44 { 45 Node *temp=myqueue.front(); 46 myqueue.pop(); 47 for(int i=0;i<maxn;i++) 48 { 49 if(temp->next[i] != NULL) 50 { 51 if(temp == root) 52 temp->next[i]->fail=root; 53 else 54 { 55 Node *p=temp->fail; 56 while(p != NULL) 57 { 58 if(p->next[i] != NULL) 59 { 60 temp->next[i]->fail=p->next[i]; 61 break; 62 } 63 p=p->fail; 64 } 65 if(p == NULL) 66 temp->next[i]->fail=root; 67 } 68 myqueue.push(temp->next[i]); 69 } 70 } 71 } 72 } 73 74 int Query(Node *root,const char *s) 75 { 76 Node *p=root; 77 int num[1010]; 78 memset(num,0,sizeof(num)); 79 while(*s != '\0') 80 { 81 if(!is_upper(*s)) 82 { 83 p=root; 84 s++; 85 continue; 86 } 87 while(p->next[*s-'A'] == NULL && p != root) 88 p=p->fail; 89 p=p->next[*s-'A']; 90 if(p == NULL) 91 p=root; 92 Node *temp=p; 93 while(temp != root) 94 { 95 num[temp->id]++; 96 temp=temp->fail; 97 } 98 s++; 99 } 100 for(int i=1;i <= N;++i) 101 if(num[i]) 102 printf("%s: %d\n",str[i],num[i]); 103 } 104 char buf[2000010]; 105 int main() 106 { 107 while(~scanf("%d",&N)) 108 { 109 Node *root=new Node(); 110 for(int i=1;i <= N;++i) 111 { 112 scanf("%s",str[i]); 113 Build_Tire(root,str[i],i); 114 } 115 Build_fail(root); 116 scanf("%s",buf); 117 Query(root,buf); 118 } 119 }