【pku3691+pku2778】ac自动机 动态规划

再讲题目之前,先讲讲ac自动机吧

看到ac这么吉利的东西,学会这什么ac自动机的欲望便来了

ac自动机全名Aho-Corasick automation,挺长的,但经验告诉我们,名字越长往往编出来的代码越短,所以不要被这么虎的名字给唬住了

好了,进入正题

ac自动机就是用来进行多串模式匹配的一种算法(不算是一种什么神奇的数据结构吧),它差不多就等于trie+kmp

这个算法的思想非常简单,就在字母树上弄个next指针(相当于kmp中的next函数),然后对于每一篇文章我们就可以根据这棵字母树来O(len)的得到那些单词出现过(貌似要统计出现个数有难度,这恐怕就是这个算法的局限性吧)

这个算法的关键就是计算next[i],方法如下:

  对于每个结点i,若它就是root,则next[i]=0,否则

  在i的父亲的next找父链(就是一路j:=next[j]上去,显然不能算进i的父亲)上找到第一个点的儿子中有i带的字符的点,

next[i]=这个儿子,如果找不到,则next[i]=root

就这么简单,具体实现起来的话广搜就可以了

然后,给了一段文章,我们要拿他与给定的单词进行匹配,就用刚才做好的字母树+next指针直接做就可以了(像kmp那样)

特别要注意,每匹配完一位,就要在next链上往回找有没有单词恰好在这一位完成匹配,而已经出现了的单词,我们可以直接把它的标记去掉就可以了(下面的代码中带!!的地方需注意)

实现起来有个小的改动可以让代码更简洁,那就是把字母树中的c[0,i]赋为1,那么next链到底时,再直接用c[0,i]就可以回到root了(我的root=1)就不用每次(k<>root)and ...了,可以显得漂亮一点

下面给出我的ac_auto的模板

  

第一次写这个调了几个小时才过(就是!!那里一直出问题),后来才发现每个用ac自动机的题目都要注意这里!

 

讲完了算法,就来看看题目吧

pku3691

大意:给若干个单词,一段文章,要求这段文章至少改动几个才能不含任何一个单词,字母只有ACGT

分析:

   这个题dp的方向很明显,只是状态的设计有点难度(在学会ac自动机之前,咳咳,我应该是做不出的)

   那么我就先入为主了,考虑怎么在自动机的那棵字母树上做文章

   可以想到如果匹配完了原串的前i位,当前到了字母树的j号结点,只要有了这个i和j就能够无后效地表示出整个匹配的状态了,那么算法就出来了

算法:

   记:

   f[i,j]表示匹配完了原串的前i位,当前到了字母树的j号结点的最少要改动的个数,转移就枚举第i+1位改成什么或者不改,用上述算法推到下一个状态就可以了,注意不能转移到的结点,要求不能成功匹配任意一个单词

   边界f[0,1]=0,答案min{f[len,i]}(word[i]=false)

需要注意的是每要转移到一个结点,就得在next链上扫一遍,看有没有word[i]为true,有就不能转移了(上面提到过的),还有麻烦的输出格式和ansistring(我wa了3次格式,1次ansistring),多组数据还得记得清空数组

代码:

 

pku2778

大意:给你若干个单词,求长度为n的dna串(只含'A''C''G''T')中不含任何一个单词的串的个数(mod 100000)(n<=200000000)

分析及算法:

   同2778类似的,dp的解题方向不会错

   这个题目中,n这个天文数字般的范围似乎在告诉我们这题用是矩阵加速的dp题,那么我就只讲转移矩阵的构造了,关于矩阵优化你可以看网上其他的资料

   对于字母树中的结点i,枚举下一个字符是什么,到了结点j,只要没有一个单词匹配成功(还是那个要注意的地方,要在next链上扫一遍)就可以转移,inc(g[i,j])即可

   再快速幂,ans=sigma(f[1,i]) mod mo (word[i]=false) (我的root=1)

代码:

这道题写的相当流畅,一次ac,感觉反正是越来越好

 

好了,至此,ac自动机应该差不多就这样了吧,发现自动机主要是用来优化有关多串模式匹配的dp中的状态表示,以后碰到题目得往这方面想想了。希望ac自动机能给我们带来更多ac的喜悦吧!

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值