• [HNOI2006]最短母串问题 --- AC自动机 + 隐式图搜索


    [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自动机中一个点可能是很多串的结尾,因此预处理转移状态时,要根据串的不同状压,而不是单一的赋值。

    细节可以自己思考思考。

    代码在此

  • 相关阅读:
    MySQL--lsblk命令查看块设备
    MySQL--linux IO调度算法
    一致性哈希
    MySQL--查询表统计信息
    MySQL--区分表名大小写
    MySQL--Online DDL
    MySQL--MODIFY COLUMN和ALTER COLUMN
    MySQL--修改表字段
    MySQL--增加或修改列注释
    鼠标事件
  • 原文地址:https://www.cnblogs.com/reverymoon/p/8869586.html
Copyright © 2020-2023  润新知