专题训练之AC自动机

Posted jackyan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了专题训练之AC自动机相关的知识,希望对你有一定的参考价值。

推荐博客:http://www.cnblogs.com/kuangbin/p/3164106.html AC自动机小结

https://blog.csdn.net/creatorx/article/details/71100840 AC自动机最详细的解释

2006年国家集训队论文:Trie图的构建、活用与改进 王赟

 

 

1.(HDOJ2222)http://acm.hdu.edu.cn/showproblem.php?pid=2222

题意:求目标串中出现了几个模式串。

分析:AC自动机模板题

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<queue>
  6 using namespace std;
  7 const int maxn=500010;
  8 
  9 struct Trie
 10 {
 11     int nxt[maxn][26],fail[maxn],end[maxn]; //nxt为字典树, fail相当于kmp中的nxt数组, end对单词结尾做标记 
 12     int root,L;  //L相当于字典树中的sz ,root为根节点(即;0) 
 13     int newnode() //初相当于始化一个字典树上的节点 
 14     {
 15         for ( int i=0;i<26;i++ ) nxt[L][i]=-1;
 16         end[L++]=0;
 17         return L-1;
 18     }
 19     void init()
 20     {
 21         L=0;
 22         root=newnode();
 23     }
 24     void insert(char buf[]) //大致于字典树插入过程相同 
 25     {
 26         int len=strlen(buf);
 27         int now=root;
 28         for ( int i=0;i<len;i++ )
 29         {
 30             int x=buf[i]-\'a\';
 31             if ( nxt[now][x]==-1 ) nxt[now][x]=newnode();
 32             now=nxt[now][x];
 33         }
 34         end[now]++; //在单词结尾处做标记 
 35     }
 36     void build()  //相当于kmp的操作 
 37     {
 38         queue<int>que;
 39         fail[root]=root; //根节点初始化为0(即其本身)
 40         for (int i=0;i<26;i++ )
 41         {
 42             if ( nxt[root][i]==-1 ) nxt[root][i]=root;
 43             else //Trie中已经构建的节点 
 44             {
 45                 int x=nxt[root][i];
 46                 fail[x]=root;
 47                 que.push(x);
 48             }
 49         }
 50         while ( !que.empty() )
 51         {
 52             int now=que.front();
 53             que.pop();
 54             for ( int i=0;i<26;i++ )
 55             {
 56                 if ( nxt[now][i]==-1 ) //无后继点 
 57                     nxt[now][i]=nxt[fail[now]][i];//类似于kmp中求nxt数组一样 
 58                 else //存在下一个节点 
 59                 {
 60                     int x=nxt[now][i];
 61                     fail[x]=nxt[fail[now]][i];//失配指针指向他父节点的失配指针的下一个相同字符处 
 62                     que.push(x);
 63                 }
 64             }
 65         }
 66     }
 67     int query(char buf[]) //相当于字典树中的访问操作 
 68     {
 69         int len=strlen(buf);
 70         int now=root;
 71         int res=0;
 72         for ( int i=0;i<len;i++ ) 
 73         //沿着整个文本串移动,每移动到一个字符(节点) 时,通过失配指针不断找寻模式串 ,重点为源头,找到一个就将其标记清除 
 74         {
 75             now=nxt[now][buf[i]-\'a\'];
 76             int tmp=now;
 77             while ( tmp!=root )
 78             {
 79                 res+=end[tmp];
 80                 end[tmp]=0;
 81                 tmp=fail[tmp];
 82             }
 83         }
 84         return res; //返回单词个数 
 85     }
 86     void debug()
 87     {
 88         for ( int i=0;i<L;i++ )
 89         {
 90             printf("%id=%3d,fail=%3d,end=%3d,chi=[",i,fail[i],end[i]);
 91             for ( int j=0;j<26;j++ ) printf("%2d",nxt[i][j]);
 92             printf("]\\n");
 93         }
 94     }
 95 };
 96 char buf[maxn*2];
 97 Trie ac;
 98 int main()
 99 {
100     int T,n;
101     scanf("%d",&T);
102     while ( T-- )
103     {
104         scanf("%d",&n);
105         ac.init();
106         for ( int i=0;i<n;i++ )
107         {
108             scanf("%s",buf);
109             ac.insert(buf);
110         }
111         ac.build();
112         scanf("%s",buf);
113         printf("%d\\n",ac.query(buf));
114     }
115     return 0;
116 }
AC自动机模板(含解释) 
  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<queue>
  6 using namespace std;
  7 const int maxn=500010;
  8 const int maxm=26;
  9 
 10 struct Trie
 11 {
 12     int nxt[maxn][maxm],fail[maxn],end[maxn]; 
 13     int root,L;   
 14     int newnode()  
 15     {
 16         for ( int i=0;i<maxm;i++ ) nxt[L][i]=-1;
 17         end[L++]=0;
 18         return L-1;
 19     }
 20     void init()
 21     {
 22         L=0;
 23         root=newnode();
 24         memset(end,0,sizeof(end));
 25     }
 26     void insert(char buf[]) 
 27     {
 28         int len=strlen(buf);
 29         int now=root;
 30         for ( int i=0;i<len;i++ )
 31         {
 32             int x=buf[i]-\'a\';
 33             if ( nxt[now][x]==-1 ) nxt[now][x]=newnode();
 34             now=nxt[now][x];
 35         }
 36         end[now]++; 
 37     }
 38     void build()   
 39     {
 40         queue<int>que;
 41         fail[root]=root; 
 42         for (int i=0;i<maxm;i++ )
 43         {
 44             if ( nxt[root][i]==-1 ) nxt[root][i]=root;
 45             else 
 46             {
 47                 int x=nxt[root][i];
 48                 fail[x]=root;
 49                 que.push(x);
 50             }
 51         }
 52         while ( !que.empty() )
 53         {
 54             int now=que.front();
 55             que.pop();
 56             for ( int i=0;i<maxm;i++ )
 57             {
 58                 if ( nxt[now][i]==-1 ) 
 59                     nxt[now][i]=nxt[fail[now]][i];
 60                 else 
 61                 {
 62                     int x=nxt[now][i];
 63                     fail[x]=nxt[fail[now]][i];
 64                     que.push(x);
 65                 }
 66             }
 67         }
 68     }
 69     int query(char buf[]) 
 70     {
 71         int len=strlen(buf);
 72         int now=root;
 73         int res=0;
 74         for ( int i=0;i<len;i++ ) 
 75         {
 76             int x=buf[i]-\'a\';
 77             now=nxt[now][x];
 78             int tmp=now;
 79             while ( tmp!=root )
 80             {
 81                 res+=end[tmp];
 82                 end[tmp]=0;
 83                 tmp=fail[tmp];
 84             }
 85         }
 86         return res; 
 87     }
 88     void debug()
 89     {
 90         for ( int i=0;i<L;i++ )
 91         {
 92             printf("%id=%3d,fail=%3d,end=%3d,chi=[",i,fail[i],end[i]);
 93             for ( int j=0;j<26;j++ ) printf("%2d",nxt[i][j]);
 94             printf("]\\n");
 95         }
 96     }
 97 };
 98 char buf[maxn*2];
 99 Trie ac;
100 int main()
101 {
102     int T,n;
103     scanf("%d",&T);
104     while ( T-- )
105     {
106         scanf("%d",&n);
107         ac.init();
108         for ( int i=0;i<n;i++ )
109         {
110             scanf("%s",buf);
111             ac.insert(buf);
112         }
113         ac.build();
114         scanf("%s",buf);
115         printf("%d\\n",ac.query(buf));
116     }
117     return 0;
118 }
HDOJ2222

 

2.(HDOJ2896)http://acm.hdu.edu.cn/showproblem.php?pid=2896

分析:只需要将原模板中的end[i]标记为是第几个模式串的id(本来记录的是数量),再另外设置一个bool型的vis数组,当tmp指针访问到某一单词的结尾时,将编号为该单词的id的数在vis数组中标为true。同时注意是所有的ascii而不是只有小写英文字母,nxt数组的第二维开128的大小

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<queue>
  5 using namespace std;
  6 const int maxn=500010;
  7 const int maxm=128;
  8 const int maxk=510;
  9 char buf[maxn*2];
 10 bool vis[maxk];
 11 
 12 struct Trie
 13 {
 14     int nxt[maxn][maxm],end[maxn],fail[maxn];
 15     int root,L;
 16     int newnode()
 17     {
 18         for ( int i=0;i<maxm;i++ ) nxt[L][i]=-1;
 19         end[L++]=0;
 20         return L-1; 
 21     }
 22     void init()
 23     {
 24         L=0;
 25         root=newnode();
 26         memset(end,0,sizeof(end));
 27     }
 28     void insert(char buf[],int id)
 29     {
 30         int len=strlen(buf);
 31         int now=root;
 32         for ( int i=0;i<len;i++ )
 33         {
 34             int x=buf[i];
 35             if ( nxt[now][x]==-1 ) nxt[now][x]=newnode();
 36             now=nxt[now][x];
 37         }
 38         end[now]=id;
 39     }
 40     void build()
 41     {
 42         queue<int>que;
 43         fail[root]=root;
 44         for ( int i=0;i<maxm;i++ )
 45         {
 46             if ( nxt[root][i]==-1 ) nxt[root][i]=root;
 47             else 
 48             {
 49                 int x=nxt[root][i];
 50                 fail[x]=root;
 51                 que.push(x);
 52             }
 53         }
 54         while ( !que.empty() )
 55         {
 56             int now=que.front();
 57             que.pop();
 58             for ( int i=0;i<maxm;i++ )
 59             {
 60                 if ( nxt[now][i]==-1 ) nxt[now][i]=nxt[fail[now]][i];
 61                 else
 62                 {
 63                     int x=nxt[now][i];
 64                     fail[x]=nxt[fail[now]][i];
 65                     que.push(x);
 66                 }
 67             }
 68         }
 69     }
 70     bool query(char buf[])
 71     {
 72         int len=strlen(buf);
 73         int now=root;
 74         bool flag=false;
 75         for ( int i=0;i<len;i++ )
 76         {
 77             int x=buf[i];
 78             now=nxt[now][x];
 79             int tmp=now;
 80             while ( tmp!=root )
 81             {
 82                 if ( end[tmp]!=0 ) {
 83                     vis[end[tmp]]=true;
 84                     flag=true;
 85                 }
 86                 tmp=fail[tmp];
 87              } 
 88         }
 89         return flag;
 90     }
 91 };
 92 Trie ac;
 93 int main()
 94 {
 95     int T,n,m,ans;
 96     while ( scanf("%d",&n)!=EOF )
 97     {
 98         ans=0;
 99         ac.init();
100         for ( int i=1;i<=n;i++ )
101         {
102             scanf("%s",buf);
103             ac.insert(buf,i);
104         }
105         ac.build();
106         scanf("%d",&m);
107         for ( int i=1;i<=m;i++ )
108         {
109             memset(vis,false,sizeof(vis));
110             scanf("%s",buf);
111             if ( ac.query(buf) ) {
112                 printf("web %d:",i);
113                 for ( int j=1;j<=n;j++ )
114                 {
115                     if ( vis[j] ) printf(" %d",j);
116                 }
117                 printf("\\n");
118                 ans++;
119             }
120         }
121         printf("total: %d\\n",ans);
122     }
123     return 0;
124 }
HDOJ2896

 

3.(HDOJ3065)http://acm.hdu.edu.cn/showproblem.php?pid=3065

分析:只需要将上一题的bool型改成int型数组输出即可

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<queue>
  5 using namespace std;
  6 const int maxn=500010;
  7 const int maxq=2000010;
  8 const int maxm=128;
  9 const int maxk=1010;
 10 char buf[maxq];
 11 int vis[maxk];
 12 char s[maxk][55];
 13 
 14 struct Trie
 15 {
 16     int nxt[maxn][maxm],end[maxn],fail[maxn];
以上是关于专题训练之AC自动机的主要内容,如果未能解决你的问题,请参考以下文章

UESTC 电子科大专题训练 数据结构 N

专题字符串专题小结(AC自动机 + 后缀自动机)

UESTC 电子科大专题训练 数据结构 J

「kuangbin带你飞」专题十七 AC自动机

UESTC 电子科大专题训练 数论 E

UESTC 电子科大专题训练 数据结构 L