[HNOI2006]最短母串问题

题目描述:

给定n个字符串(S1,S2.....,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,......,Sn)都是T的子串。

输入格式:

第一行是一个正整数n(n<=12),表示给定的字符串的个数。
以下的n行,每行有一个全由大写字母组成的字符串。每个字符串的长度不超过50.
 
输出格式:
只有一行,为找到的最短的字符串T。在保证最短的前提下,
如果有多个字符串都满足要求,那么必须输出按字典序排列的第一个。
 
 

考虑T匹配了所有的S串,这相当于一个状态

考虑状压,将已经匹配了多少S串压成一个状态。

\(dp(i,j)\)表示当前到了 i 号节点(AC自动机中),匹配的情况是 j

不难发现,要寻找的是距离状态\(dp(0,0)\)转移次数最少的点。

因此,可以考虑用隐式图搜索bfs来代替直接dp

怎么转移?

我们需要知道到达每个节点已经匹配了哪些点。

因此,让所有串在AC自动机的尾端逆着fail树给予状态。

转移比较好想,\(dp(i,j) ---> dp(v,j | state(v))\)

当我们第一次到达状态\(dp(..., 2 ^ {n} - 1)\)时,意味着我们已经构造出了一个串。

听起来没有什么问题。

但题目有个诡异的要求:字典序最小。

这对于bfs来说并不难构造,优先走'A'扩展,再'B'......

这样,字典序一定是最小的。

现在解也出来了,怎么往回找来得出这个串呢?

因此,额外记录一个\(pre(i)\)表示 i 号状态被转移的状态,\(letter(i)\),表示 i 号状态被转移的字母。

往回一直搜到初始状态即可。

完了吗?

并没有,本题还有卡空间的恶心条件。

我承认,我真不知道怎么卡,看了下题解(......)

1.用stl的队列,空间消耗是随时的。

2.用\(vis(i, j)\)来表示\((i,j)\)这个状态有没有被搜索过,如果有,就不再加入队列。

然后注意一下,我的实现出了点小差错。

后来发现是AC自动机中一个点可能是很多串的结尾,因此预处理转移状态时,要根据串的不同状压,而不是单一的赋值。

细节可以自己思考思考。

代码在此

最新文章

  1. SparkStreaming实现Exactly-Once语义
  2. dict与list的in 操作的速度
  3. Python之import
  4. 【BZOJ-3996】线性代数 最小割-最大流
  5. Springmvc4 com/fasterxml/jackson/core/JsonProcessingException
  6. Hadoop入门进阶课程4--HDFS原理及操作
  7. iOS闹钟实现
  8. Jquery简单动画的实现记录
  9. Python爬虫 Cookie的使用
  10. 关于QT按键信号槽的总结(原创)
  11. 安装Apache Maven
  12. JavaScript 轮播图实例
  13. Flask入门之SQLAlchemy配置与数据库连接
  14. 痞子衡嵌入式:常用的数据差错控制技术(1)- 重复校验(Repetition Code)
  15. 【算法】LeetCode算法题-Longest Common Prefix
  16. 解决idea下载依赖包慢到出奇
  17. SPI 核软件调试记录
  18. React笔记-事件分发
  19. Spring 多数据源事务配置问题
  20. Windows下Visual Studio 2013编译Lua 5.2.3

热门文章

  1. Bzoj2300 / 洛谷P2521 [HAOI2011]防线修建
  2. git创建新分支推送到远程
  3. TinyOS 代码分析
  4. Mysql储存过程1: 设置结束符与储存过程创建
  5. makefile里PHONY的相关介绍
  6. 谁说运维用ELK没用?我就说很有用,只是你之前不会用【转】
  7. [ python ] 网络编程(2)
  8. set -o vi AIX下shell
  9. ASP连接读写ACCESS数据库实例(转)
  10. Codeforces 821C Okabe and Boxes(模拟)