首页 > 代码库 > ac自动机小结

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 }
View Code

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 }
View Code

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 }
View Code

 

ac自动机小结