ac自动机小结
Posted Wally的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ac自动机小结相关的知识,希望对你有一定的参考价值。
关于ac自动机模板是非常重要的,在上一篇文章中已经给出了非常好用的数组类型的模板。下面的题目都是在模板之上进行略微修改就能ac的简单题
1.hdu--3065 病毒侵袭持续中
http://acm.hdu.edu.cn/showproblem.php?pid=3065
题意:统计子串在主串中出现的次数,分别打印出来
思路:由于都是大写字母所以next[][26]即可,非大写字母在查询时跳过就行。模板本身就能对字符串进行统计,所以用一个新的数组记录结果就行。
AC代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <queue> 6 #include <algorithm> 7 using namespace std; 8 const int maxn=1005*55+5; 9 int res[1005]; 10 char buf[1005][55]; 11 struct trie 12 { 13 int next[maxn][128],fail[maxn],end[maxn]; 14 int root,L; 15 int newnode() 16 { 17 for(int i=0; i<128; i++) 18 next[L][i]=-1; 19 end[L++]=-1; 20 return L-1; 21 } 22 void init() 23 { 24 L=0; 25 root=newnode(); 26 } 27 void insert(char buf[],int id) 28 { 29 int len=strlen(buf); 30 int now=root; 31 for(int i=0; i<len; i++) 32 { 33 if(next[now][buf[i]]==-1) 34 next[now][buf[i]]=newnode(); 35 now=next[now][buf[i]]; 36 } 37 end[now]=id; 38 } 39 void build() 40 { 41 queue<int>Q; 42 fail[root]=root; 43 for(int i=0; i<128; i++) 44 if(next[root][i]==-1) 45 next[root][i]=root; 46 else 47 { 48 fail[next[root][i]]=root; 49 Q.push(next[root][i]); 50 } 51 while(!Q.empty()) 52 { 53 int now=Q.front(); 54 Q.pop(); 55 for(int i=0; i<128; i++) 56 if(next[now][i]==-1) 57 next[now][i]=next[fail[now]][i]; 58 else 59 { 60 fail[next[now][i]]=next[fail[now]][i]; 61 Q.push(next[now][i]); 62 } 63 } 64 } 65 int query(char buf[]) 66 { 67 int len=strlen(buf); 68 int now=root; 69 memset(res,0,sizeof(res)); 70 for(int i=0; i<len; i++) 71 { 72 now=next[now][buf[i]]; 73 int tmp=now; 74 while(tmp!=root) 75 { 76 if(end[tmp]!=-1) 77 { 78 res[end[tmp]]++; 79 } 80 tmp=fail[tmp]; 81 } 82 } 83 return 0; 84 } 85 }; 86 trie ac; 87 char str[2000005]; 88 int main() 89 { 90 int n,m; 91 while(~scanf("%d",&n)) 92 { 93 ac.init(); 94 getchar(); 95 for(int i=1; i<=n; i++) 96 { 97 scanf("%s",buf[i]); 98 ac.insert(buf[i],i); 99 } 100 ac.build(); 101 scanf("%s",str); 102 ac.query(str); 103 for(int i=1; i<=n; i++) 104 if(res[i]) 105 printf("%s: %d\\n",buf[i],res[i]); 106 } 107 return 0; 108 }
2.hdu--5384 Danganronpa
http://acm.hdu.edu.cn/showproblem.php?pid=5384
题意:先给n个主串,再给m个子串,求每个主串中每个子串出现的次数。
思路:由于数据的原因用二维数组存放主串是不合适的,因此有三个一维数组去记录数据,问题就变得非常的简单了。还有就是string类型转成char类型的函数str.c.str()在编译器中会出错不然的话有此函数也是一种方法。
AC代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <queue> 6 #include <algorithm> 7 using namespace std; 8 const int maxn=600000+5; 9 struct trie 10 { 11 int next[maxn][26],fail[maxn],end[maxn]; 12 int root,L; 13 int newnode() 14 { 15 for(int i=0; i<26; i++) 16 next[L][i]=-1; 17 end[L++]=0; 18 return L-1; 19 } 20 void init() 21 { 22 L=0; 23 root=newnode(); 24 } 25 void insert(char buf[],int id) 26 { 27 int len=strlen(buf); 28 int now=root; 29 for(int i=0; i<len; i++) 30 { 31 if(next[now][buf[i]-\'a\']==-1) 32 next[now][buf[i]-\'a\']=newnode(); 33 now=next[now][buf[i]-\'a\']; 34 } 35 end[now]++; 36 } 37 void build() 38 { 39 queue<int>Q; 40 fail[root]=root; 41 for(int i=0; i<26; i++) 42 if(next[root][i]==-1) 43 next[root][i]=root; 44 else 45 { 46 fail[next[root][i]]=root; 47 Q.push(next[root][i]); 48 } 49 while(!Q.empty()) 50 { 51 int now=Q.front(); 52 Q.pop(); 53 for(int i=0; i<26; i++) 54 if(next[now][i]==-1) 55 next[now][i]=next[fail[now]][i]; 56 else 57 { 58 fail[next[now][i]]=next[fail[now]][i]; 59 Q.push(next[now][i]); 60 } 61 } 62 } 63 int query(char buf[],int n,int m) 64 { 65 int len=strlen(buf); 66 int now=root,cnt=0; 67 for(int i=n; i<m; i++) 68 { 69 now=next[now][buf[i]-\'a\']; 70 int tmp=now; 71 while(tmp!=root) 72 { 73 if(end[tmp]!=-1) 74 { 75 cnt+=end[tmp]; 76 } 77 tmp=fail[tmp]; 78 } 79 } 80 return cnt; 81 } 82 }; 83 trie ac; 84 char str[6000005]; 85 int a[100005],b[1000005]; 86 char buf[10005]; 87 int main() 88 { 89 int n,m,t,la; 90 while(~scanf("%d",&t)) 91 { 92 while(t--) 93 { 94 ac.init(); 95 scanf("%d%d",&n,&m); 96 getchar(); 97 la=0; 98 for(int i=1; i<=n; i++) 99 { 100 scanf("%s",buf); 101 strcpy(str+la,buf); 102 a[i]=la; 103 la=strlen(buf)+la; 104 b[i]=la; 105 } 106 for(int i=1; i<=m; i++) 107 { 108 scanf("%s",buf); 109 ac.insert(buf,i); 110 } 111 ac.build(); 112 for(int i=1; i<=n; i++) 113 { 114 printf("%d\\n",ac.query(str,a[i],b[i])); 115 } 116 } 117 } 118 return 0; 119 }
3.hdu--5880 Family View
http://acm.hdu.edu.cn/showproblem.php?pid=5880
题意:先给出m个子串(只有小写字母),再给出一个主串,如果主串包含子串则把包含部分变成 *
思路:用数组dis[]储存子串长度,当主串包含子串时,就把当前字符之前的dis[k]个字符变成 * 。由于主串大小写通用,所以大写时 -‘A’、小写时 -‘a’,否则跳过就行了。
AC代码:
1 #include <iostream> 2 #include<cstdio> 3 #include <cstring> 4 #include <queue> 5 using namespace std; 6 const int maxn=1000005; 7 char str[1000005]; 8 struct trie 9 { 10 int next[maxn][26],fail[maxn],end[maxn],dis[maxn]; 11 int root,L; 12 int newnode() 13 { 14 for(int i=0; i<26; i++) 15 next[L][i]=-1; 16 end[L++]=-1; 17 dis[maxn]=0; 18 return L-1; 19 } 20 void init() 21 { 22 L=0; 23 root=newnode(); 24 } 25 void insert(char buf[],int id) 26 { 27 int len=strlen(buf); 28 int now=root; 29 for(int i=0; i<len; i++) 30 { 31 if(next[now][buf[i]-\'a\']==-1) 32 next[now][buf[i]-\'a\']=newnode(); 33 now=next[now][buf[i]-\'a\']; 34 } 35 end[now]=id; 36 dis[now]=len; 37 } 38 void build() 39 { 40 queue<int>Q; 41 fail[root]=root; 42 for(int i=0; i<26; i++) 43 if(next[root][i]==-1) 44 next[root][i]=root; 45 else 46 { 47 fail[next[root][i]]=root; 48 Q.push(next[root][i]); 49 } 50 while(!Q.empty()) 51 { 52 int now=Q.front(); 53 Q.pop(); 54 for(int i=0; i<26; i++) 55 if(next[now][i]==-1) 56 next[now][i]=next[fail[now]][i]; 57 else 58 { 59 fail[next[now][i]]=next[fail[now]][i]; 60 Q.push(next[now][i]); 61 } 62 } 63 } 64 int query() 65 { 66 int len=strlen(str); 67 int now=root; 68 for(int i=0; i<len; i++) 69 { 70 if(str[i]>=\'a\'&&str[i]<=\'z\') 71 now=next[now][str[i]-\'a\']; 72 else if(str[i]>=\'A\'&&str[i]<=\'Z\') 73 now=next[now][str[i]-\'A\']; 74 else 75 continue; 76 int tmp=now; 77 while(tmp!=root) 78 { 79 if(end[tmp]!=-1) 80 { 81 int cnt=dis[tmp],j=i; 82 while(cnt--) 83 { 84 str[j--]=\'*\'; 85 } 86 } 87 tmp=fail[tmp]; 88 } 89 } 90 return 0; 91 } 92 }; 93 trie ac; 94 int main() 95 { 96 int t,m; 97 while(~scanf("%d",&t)) 98 { 99 while(t--) 100 { 101 ac.init(); 102 scanf("%d",&m); 103 getchar(); 104 for(int i=1;i<=m;i++) 105 { 106 gets(str); 107 ac.insert(str,i); 108 } 109 ac.build(); 110 gets(str); 111 ac.query(); 112 puts(str); 113 } 114 } 115 return 0; 116 }
以上是关于ac自动机小结的主要内容,如果未能解决你的问题,请参考以下文章