博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
专题训练之AC自动机
阅读量:5220 次
发布时间:2019-06-14

本文共 6522 字,大约阅读时间需要 21 分钟。

推荐博客: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
2 #include
3 #include
4 #include
5 #include
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
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
AC自动机模板(含解释) 
1 #include
2 #include
3 #include
4 #include
5 #include
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
que; 41 fail[root]=root; 42 for (int i=0;i
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
2 #include
3 #include
4 #include
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
que; 43 fail[root]=root; 44 for ( int i=0;i
HDOJ2896

 

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

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

1 #include
2 #include
3 #include
4 #include
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
que; 45 fail[root]=root; 46 for ( int i=0;i
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
2 #include
3 #include
4 #include
5 #include
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
que; 53 fail[root]=root; 54 for (int i=0;i
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
2 #include
3 #include
4 #include
5 #include
6 #include
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
que; 52 fail[root]=root; 53 for (int i=0;i
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
2 #include
3 #include
4 #include
5 #include
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
que; 51 fail[root]=root; 52 for (int i=0;i
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

你可能感兴趣的文章
20190422 T-SQL 触发器
查看>>
[置顶] Linux终端中使用上一命令减少键盘输入
查看>>
poj1422_有向图最小路径覆盖数
查看>>
BootScrap
查看>>
[大牛翻译系列]Hadoop(16)MapReduce 性能调优:优化数据序列化
查看>>
WEB_点击一百万次
查看>>
CodeForces - 878A Short Program(位运算)
查看>>
路冉的JavaScript学习笔记-2015年1月23日
查看>>
Mysql出现(10061)错误提示的暴力解决办法
查看>>
2018-2019-2 网络对抗技术 20165202 Exp3 免杀原理与实践
查看>>
NPM慢怎么办 - nrm切换资源镜像
查看>>
CoreData 从入门到精通(四)并发操作
查看>>
Swift - UIView的常用属性和常用方法总结
查看>>
Swift - 异步加载各网站的favicon图标,并在单元格中显示
查看>>
Java编程思想总结笔记Chapter 5
查看>>
[LeetCode]662. Maximum Width of Binary Tree判断树的宽度
查看>>
WinForm聊天室
查看>>
【Python学习笔记】1.基础知识
查看>>
梦断代码阅读笔记02
查看>>
selenium学习中遇到的问题
查看>>