专题训练之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];
 17     int root,L;
 18     int newnode()
 19     {
 20         for ( int i=0;i<maxm;i++ ) nxt[L][i]=-1;
 21         end[L++]=0;
 22         return L-1; 
 23     }
 24     void init()
 25     {
 26         L=0;
 27         root=newnode();
 28         memset(end,0,sizeof(end));
 29     }
 30     void insert(char buf[],int id)
 31     {
 32         int len=strlen(buf);
 33         int now=root;
 34         for ( int i=0;i<len;i++ )
 35         {
 36             int x=buf[i];
 37             if ( nxt[now][x]==-1 ) nxt[now][x]=newnode();
 38             now=nxt[now][x];
 39         }
 40         end[now]=id;
 41     }
 42     void build()
 43     {
 44         queue<int>que;
 45         fail[root]=root;
 46         for ( int i=0;i<maxm;i++ )
 47         {
 48             if ( nxt[root][i]==-1 ) nxt[root][i]=root;
 49             else 
 50             {
 51                 int x=nxt[root][i];
 52                 fail[x]=root;
 53                 que.push(x);
 54             }
 55         }
 56         while ( !que.empty() )
 57         {
 58             int now=que.front();
 59             que.pop();
 60             for ( int i=0;i<maxm;i++ )
 61             {
 62                 if ( nxt[now][i]==-1 ) nxt[now][i]=nxt[fail[now]][i];
 63                 else
 64                 {
 65                     int x=nxt[now][i];
 66                     fail[x]=nxt[fail[now]][i];
 67                     que.push(x);
 68                 }
 69             }
 70         }
 71     }
 72     void query(char buf[])
 73     {
 74         int len=strlen(buf);
 75         int now=root;
 76         for ( int i=0;i<len;i++ )
 77         {
 78             int x=buf[i];
 79             now=nxt[now][x];
 80             int tmp=now;
 81             while ( tmp!=root )
 82             {
 83                 if ( end[tmp]!=0 ) vis[end[tmp]]++;
 84                 tmp=fail[tmp];
 85              } 
 86         }
 87         return;
 88     }
 89 };
 90 Trie ac;
 91 int main()
 92 {
 93     int T,n,m;
 94     while ( scanf("%d",&n)!=EOF )
 95     {
 96         ac.init();
 97         for ( int i=1;i<=n;i++ )
 98         {
 99             scanf("%s",s[i]);
100             ac.insert(s[i],i);
101         }
102         ac.build();
103         scanf("%s",buf);
104         memset(vis,0,sizeof(vis));
105         ac.query(buf);
106         for ( int i=1;i<=n;i++ )
107         {
108             if ( vis[i]!=0 ) printf("%s: %d\n",s[i],vis[i]);
109         }
110     }
111     return 0;
112 }
HDOJ3065

 

4.(POJ2778)http://poj.org/problem?id=2778

题意:给出n个患病的DNA序列,问序列长度为m的,且不包含患病的DNA序列有多少种。

分析:AC自动机+乘法矩阵,https://blog.csdn.net/morgan_xww/article/details/7834801推荐此博客有较详细的解释

大致过程:将end[maxn]数组改成bool型,若为true表示该点是危险点,为false为安全点(初始时全为false)( 显然根结点是安全结点。 一个非根结点是危险结点的充要条件是: 它的路径字符串本身就是一个不良单词 ,或 它的路径字符串的后缀对应的结点(即fail[i])是危险结点)。增加longlong型的mat[maxn][maxn]数组,mat[i][j]表示节点i走一步到节点j有多少方案,当i和j都为安全点时才被计算进mat数组中(即所有满足条件的答案/不含模式串)。增加res[maxn][maxn]为mat阶乘m次后的答案。最后的答案为res[0][i](i从[0,L))的求和

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<queue>
  6 using namespace std;
  7 typedef long long ll;
  8 const int maxn=1e3+10;
  9 const int maxm=4;
 10 const int mod=1e5;
 11 
 12 struct Trie
 13 {
 14     int nxt[maxn][maxm],fail[maxn];
 15     ll mat[maxn][maxn];
 16     bool end[maxn]; 
 17     int root,L;   
 18     int newnode()  
 19     {
 20         for ( int i=0;i<maxm;i++ ) nxt[L][i]=-1;
 21         end[L++]=0;
 22         return L-1;
 23     }
 24     void init()
 25     {
 26         L=0;
 27         root=newnode();
 28         memset(end,false,sizeof(end));
 29         memset(mat,0,sizeof(mat));
 30     }
 31     int getid(char c)
 32     {
 33         if ( c=='A' ) return 0;
 34         else if ( c=='C' ) return 1;
 35         else if ( c=='T' ) return 2;
 36         else if ( c=='G' ) return 3;
 37     }
 38     void insert(char buf[]) 
 39     {
 40         int len=strlen(buf);
 41         int now=root;
 42         for ( int i=0;i<len;i++ )
 43         {
 44             int x=getid(buf[i]);
 45             if ( nxt[now][x]==-1 ) nxt[now][x]=newnode();
 46             now=nxt[now][x];
 47         }
 48         end[now]=true; 
 49     }
 50     void build()   
 51     {
 52         queue<int>que;
 53         fail[root]=root; 
 54         for (int i=0;i<maxm;i++ )
 55         {
 56             if ( nxt[root][i]==-1 ) nxt[root][i]=root;
 57             else 
 58             {
 59                 int x=nxt[root][i];
 60                 fail[x]=root;
 61                 que.push(x);
 62             }
 63         }
 64         while ( !que.empty() )
 65         {
 66             int now=que.front();
 67             que.pop();
 68             if ( end[fail[now]] ) end[now]=true;
 69             for ( int i=0;i<maxm;i++ )
 70             {
 71                 if ( nxt[now][i]==-1 ) 
 72                     nxt[now][i]=nxt[fail[now]][i];
 73                 else 
 74                 {
 75                     int x=nxt[now][i];
 76                     fail[x]=nxt[fail[now]][i];
 77                     que.push(x);
 78                 }
 79             }
 80         }
 81     }
 82     void setmat()
 83     {
 84         for ( int i=0;i<L;i++ )
 85         {
 86             for ( int j=0;j<maxm;j++ )
 87             {
 88                 if ( !end[i] && !end[nxt[i][j]] ) mat[i][nxt[i][j]]++;
 89             }
 90         }
 91     }
 92     void debug()
 93     {
 94         for ( int i=0;i<L;i++ )
 95         {
 96             for ( int j=0;j<L;j++ ) printf("%d ",mat[i][j]);
 97             printf("\n");
 98         }
 99     }
100     ll res[maxn][maxn],tmp[maxn][maxn];
101     void mul(ll a[][maxn],ll b[][maxn])
102     {
103         for ( int i=0;i<L;i++ )
104         {
105             for ( int j=0;j<L;j++ )
106             {
107                 tmp[i][j]=0;
108                 for ( int k=0;k<L;k++ ) tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j])%mod;
109             }
110         }
111         for ( int i=0;i<L;i++ )
112         {
113             for ( int j=0;j<L;j++ ) a[i][j]=tmp[i][j]%mod;
114         }
115     }
116     void pow(ll k)
117     {
118         memset(res,0,sizeof(res));
119         for ( int i=0;i<L;i++ ) res[i][i]=1;
120         while ( k )
121         {
122             if ( k&1 ) mul(res,mat);
123             mul(mat,mat);
124             k/=2;
125         }
126     }
127 };
128 char buf[105];
129 Trie ac;
130 int main()
131 {
132     int T,n,m;
133     ll ans;
134     while ( scanf("%d%d",&n,&m)!=EOF )
135     {
136         ac.init();
137         for ( int i=0;i<n;i++ )
138         {
139             scanf("%s",buf);
140             ac.insert(buf);
141         }
142         ac.build();
143         ac.setmat();
144         ac.pow(m);
145         ans=0;
146         for ( int i=0;i<ac.L;i++ ) 
147         {
148             ans=(ans+ac.res[0][i])%mod;
149         }
150         printf("%lld\n",ans);
151     }
152     return 0;
153 }
POJ2778

 

5.(HDOJ2243)http://acm.hdu.edu.cn/showproblem.php?pid=2243

分析:和上题类似,不过不同之处有两点:1.该题是至少包含一个模式串(上一题是一个都没有) 2.该题最后得到的长度<=n(上一题是刚好为n)

分析:大致做法于上题相同,难点在于如何解决两个不同。对于第一个不同采用反面的想法(即算出所有答案减去不含模式串的答案就为当前的答案),对于第二个考虑通过矩阵构造的方法

记初始的mat矩阵为A,若想求得A^1+A^2……+A^n则需要构造一个这样的矩阵。

注意:将运算过程中的变量和矩阵的元素定义为unsigned long long,就能实现自动对2^64自动取mod(即不用特地去取模)。

特别注意两个矩阵的构造方法(一个是求26^1到26^n的求和,另外一个是A^1到A^n的求和),关注几次幂和矩阵大小

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<queue>
  6 #include<cmath>
  7 using namespace std;
  8 typedef long long ll;
  9 typedef unsigned long long ull;
 10 const int maxn=1e3+10;
 11 const int maxm=26;
 12 //const ll mod=0x3f3f3f3f;
 13 
 14 struct Trie
 15 {
 16     int nxt[maxn][maxm],fail[maxn];
 17     ull mat[maxn][maxn],num[4][4];
 18     bool end[maxn]; 
 19     int root,L;   
 20     int newnode()  
 21     {
 22         for ( int i=0;i<maxm;i++ ) nxt[L][i]=-1;
 23         end[L++]=0;
 24         return L-1;
 25     }
 26     void init()
 27     {
 28         L=0;
 29         root=newnode();
 30         memset(end,false,sizeof(end));
 31         memset(mat,0,sizeof(mat));
 32     }
 33     int getid(char c)
 34     {
 35         return c-'a';
 36     }
 37     void insert(char buf[]) 
 38     {
 39         int len=strlen(buf);
 40         int now=root;
 41         for ( int i=0;i<len;i++ )
 42         {
 43             int x=getid(buf[i]);
 44             if ( nxt[now][x]==-1 ) nxt[now][x]=newnode();
 45             now=nxt[now][x];
 46         }
 47         end[now]=true; 
 48     }
 49     void build()   
 50     {
 51         queue<int>que;
 52         fail[root]=root; 
 53         for (int i=0;i<maxm;i++ )
 54         {
 55             if ( nxt[root][i]==-1 ) nxt[root][i]=root;
 56             else 
 57             {
 58                 int x=nxt[root][i];
 59                 fail[x]=root;
 60                 que.push(x);
 61             }
 62         }
 63         while ( !que.empty() )
 64         {
 65             int now=que.front();
 66             que.pop();
 67             if ( end[fail[now]] ) end[now]=true;
 68             for ( int i=0;i<maxm;i++ )
 69             {
 70                 if ( nxt[now][i]==-1 ) 
 71                     nxt[now][i]=nxt[fail[now]][i];
 72                 else 
 73                 {
 74                     int x=nxt[now][i];
 75                     fail[x]=nxt[fail[now]][i];
 76                     que.push(x);
 77                 }
 78             }
 79         }
 80     }
 81     void setmat()
 82     {
 83         for ( int i=0;i<L;i++ )
 84         {
 85             for ( int j=0;j<maxm;j++ )
 86             {
 87                 if ( !end[i] && !end[nxt[i][j]] ) mat[i][nxt[i][j]]++;
 88             }
 89         }
 90         for ( int i=0;i<=L;i++ ) mat[i][L]=1;
 91     }
 92     void debug()
 93     {
 94         for ( int i=0;i<L;i++ )
 95         {
 96             for ( int j=0;j<L;j++ ) printf("%d ",mat[i][j]);
 97             printf("\n");
 98         }
 99     }
100     ull res[maxn][maxn],tmp[maxn][maxn];
101     void mul(ull a[][maxn],ull b[][maxn],ll l)
102     {
103         for ( int i=0;i<l;i++ )
104         {
105             for ( int j=0;j<l;j++ )
106             {
107                 tmp[i][j]=0;
108                 for ( int k=0;k<l;k++ ) tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j]);
109             }
110         }
111         for ( int i=0;i<l;i++ )
112         {
113             for ( int j=0;j<l;j++ ) a[i][j]=tmp[i][j];
114         }
115     }
116     void pow(ll k,ll l)
117     {
118         memset(res,0,sizeof(res));
119         for ( int i=0;i<l;i++ ) res[i][i]=1;
120         while ( k )
121         {
122             if ( k&1 ) mul(res,mat,l);
123             mul(mat,mat,l);
124             k/=2;
125         }
126     }
127 };
128 char buf[10];
129 Trie ac;
130 int main()
131 {
132     int T,n,m;
133     ull ans,sum;
134     while ( scanf("%d%d",&n,&m)!=EOF )
135     {
136         ac.init();
137         for ( int i=0;i<n;i++ )
138         {
139             scanf("%s",buf);
140             ac.insert(buf);
141         }
142         ac.build();
143         ac.setmat();
144         //ac.debug();
145         ac.pow(m,ac.L+1);
146         ans=0;
147         for ( int i=0;i<=ac.L;i++ ) 
148         {
149             ans=(ans+ac.res[0][i]);
150         }
151         ac.mat[0][0]=26;
152         ac.mat[0][1]=ac.mat[1][1]=1;
153         ac.mat[1][0]=0;
154         ac.pow(m+1,2);
155         sum=ac.res[0][1];
156         ans=(sum-ans);
157         printf("%I64u\n",ans);
158     }
159     return 0;
160 }
HDOJ2243

 

6.(HDOJ2457)http://acm.hdu.edu.cn/showproblem.php?pid=2457

题意:给定N(N <= 50)个长度不超过20的模式串,再给定一个长度为M(M <= 1000)的目标串S,求在目标串S上最少改变多少字符,可以使得它不包含任何的模式串(所有串只有ACGT四种字符)

分析:AC自动机+dp。先通过AC自动机得到Trie图,然后通过Trie图去构建字符串。设dp[i][j]表示长度为i,状态为j(这里的状态和节点的编号相对应)的字符串变成目标串前i位需要的最少操作次数。初始化:dp[0][0]=0(初始状态),其他一律设置为inf。具体转移及细节见代码

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<queue>
  6 using namespace std;
  7 const int maxn=1010;
  8 const int maxm=4;
  9 const int inf=1e9;
 10 int dp[maxn][maxn];
 11 
 12 struct Trie
 13 {
 14     int nxt[maxn][maxm],fail[maxn];
 15     bool end[maxn]; 
 16     int root,L;   
 17     int newnode()  
 18     {
 19         for ( int i=0;i<maxm;i++ ) nxt[L][i]=-1;
 20         end[L++]=0;
 21         return L-1;
 22     }
 23     void init()
 24     {
 25         L=0;
 26         root=newnode();
 27         memset(end,false,sizeof(end));
 28     }
 29     int getid(char c)
 30     {
 31         if ( c=='A' ) return 0;
 32         else if ( c=='T' ) return 1;
 33         else if ( c=='G' ) return 2;
 34         else if ( c=='C' ) return 3;
 35     }
 36     void insert(char buf[]) 
 37     {
 38         int len=strlen(buf);
 39         int now=root;
 40         for ( int i=0;i<len;i++ )
 41         {
 42             int x=getid(buf[i]);
 43             if ( nxt[now][x]==-1 ) nxt[now][x]=newnode();
 44             now=nxt[now][x];
 45         }
 46         end[now]=true; 
 47     }
 48     void build()   
 49     {
 50         queue<int>que;
 51         fail[root]=root; 
 52         for (int i=0;i<maxm;i++ )
 53         {
 54             if ( nxt[root][i]==-1 ) nxt[root][i]=root;
 55             else 
 56             {
 57                 int x=nxt[root][i];
 58                 fail[x]=root;
 59                 que.push(x);
 60             }
 61         }
 62         while ( !que.empty() )
 63         {
 64             int now=que.front();
 65             que.pop();
 66             if ( end[fail[now]] ) end[now]=true;
 67             for ( int i=0;i<maxm;i++ )
 68             {
 69                 if ( nxt[now][i]==-1 ) 
 70                     nxt[now][i]=nxt[fail[now]][i];
 71                 else 
 72                 {
 73                     int x=nxt[now][i];
 74                     fail[x]=nxt[fail[now]][i];
 75                     que.push(x);
 76                 }
 77             }
 78         }
 79     }
 80     int query(char buf[]) 
 81     {
 82         int len=strlen(buf);
 83         int now=root;
 84         int res=0;
 85         for ( int i=0;i<len;i++ ) 
 86         {
 87             int x=getid(buf[i]);
 88             now=nxt[now][x];
 89             int tmp=now;
 90             while ( tmp!=root )
 91             {
 92                 res+=end[tmp];
 93                 end[tmp]=0;
 94                 tmp=fail[tmp];
 95             }
 96         }
 97         return res; 
 98     }
 99 };
100 char buf[maxn];
101 Trie ac;
102 int main()
103 {
104     int n,h=0;
105     while ( scanf("%d",&n)!=EOF && n )
106     {
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         int len=strlen(buf);
116         for ( int i=0;i<=len;i++ )
117             for ( int j=0;j<ac.L;j++ ) dp[i][j]=inf;
118         dp[0][ac.root]=0;
119         for ( int i=0;i<len;i++ )
120             for ( int j=0;j<ac.L;j++ )
121                 if ( dp[i][j]<inf ) 
122                 {
123                     for ( int k=0;k<maxm;k++ )
124                     {
125                         int news=ac.nxt[j][k];
126                         if ( ac.end[news] ) continue;
127                         int x=ac.getid(buf[i]);
128                         int add;
129                         if ( x==k ) add=0;
130                         else add=1;
131                         dp[i+1][news]=min(dp[i+1][news],add+dp[i][j]);
132                     }
133                 }
134         int ans=inf;
135         for ( int j=0;j<ac.L;j++ ) ans=min(ans,dp[len][j]);
136         printf("Case %d: ",++h);
137         if ( ans==inf ) printf("-1\n");
138         else printf("%d\n",ans);
139     }
140     return 0;
141 }
HDOJ2457

 

待做:1.(POJ1699)http://poj.org/problem?id=1699

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

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

4.(HDOJ3247)http://acm.hdu.edu.cn/showproblem.php?pid=3247

小结:AC自动机一般适用于多串匹配,往往是通过构造去求一些关于不含模式串的字符串类型的题目,构造过程往往在Trie图中按照一定要求(一般为是否该点/状态为安全点)进行,Trie图中的每一个点代表一个状态,从一个点有maxm(字符类型的总个数)个移动方向,危险点往往不参与构造(即只有安全点才参与)。

转载于:https://www.cnblogs.com/HDUjackyan/p/9043255.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值