【题解】最短母串

题目大意

??有\(n\)个字符串\(s_1,s_2,\dots,s_n\),求一个最短的字符串\(S\),使这\(n\)个字符串都是\(S\)的子串。

?

题解

??我们先对这\(n\)个字符串建AC自动机,这里我们对于Trie上的结点\(i\),定义一个状态\(state_i\),表示第\(i\)个结点对应的字符串,包含的题目中给出的哪些字符串。
??我们可以从Trie上的根节点,按照字典序BFS,我们用\(f\)表示当前经过的所有结点的包含的所有字符串,显然,当\(f\)包含所有字符串时,此时即为最优解。具体可以看代码理解,没什么好说的。

#include <iostream>
#include <cstdio>
#include <cstring>

#define MAX_N (12 + 5)
#define MAX_S ((1 << 12) + 5)
#define MAX_LEN (50 + 5)

using namespace std;

struct Trie
{
    int to[30];
    int fail;
    char ch;
    int state;
};

int n;
char s[MAX_LEN];
Trie t[MAX_N * MAX_LEN];
int m = 1;
int q[MAX_N * MAX_LEN], l, r;
bool vis[MAX_N * MAX_LEN][MAX_S];
int pos[MAX_N * MAX_LEN * MAX_S], prev[MAX_N * MAX_LEN * MAX_S], f[MAX_N * MAX_LEN * MAX_S];
char ans[MAX_N * MAX_LEN];
int top;

void Insert(int state)
{
    int len = strlen(s + 1);
    int now = 1, tmp;
    for (int i = 1; i <= len; ++i)
    {
        tmp = s[i] - 'A';
        if (!t[now].to[tmp])
        {
            t[now].to[tmp] = ++m;
            t[m].ch = s[i];
        }
        now = t[now].to[tmp];
    }
    t[now].state |= state;
    return;
}

void Build()
{
    for (int i = 0; i < 26; ++i)
    {
        t[0].to[i] = 1;
    }
    q[1] = 1;
    l = r = 1;
    int now;
    while (l <= r)
    {
        now = q[l++];
        for (int i = 0; i < 26; ++i)
        {
            if (t[now].to[i])
            {
                t[t[now].to[i]].fail = t[t[now].fail].to[i];
                t[t[now].to[i]].state |= t[t[t[now].fail].to[i]].state;
                q[++r] = t[now].to[i];
            }
            else
            {
                t[now].to[i] = t[t[now].fail].to[i];
            }
        }
    }
    return;
}

void Solve()
{
    vis[1][0] = true;
    pos[0] = 1;
    int u, v;
    int now = 0, cnt = 0;
    const int lim = (1 << n) - 1;
    while (now <= cnt)
    {
        if (f[now] == lim)
        {
            while(now)
            {
                u = pos[now];
                if (t[u].ch) ans[++top] = t[u].ch;
                now = prev[now];
            }
            break;
        }
        u = pos[now];
        for (int i = 0; i < 26; ++i)
        {
            v = t[u].to[i];
            if (vis[v][f[now] | t[v].state]) continue;
            vis[v][f[now] | t[v].state] = true;
            pos[++cnt] = v;
            prev[cnt] = now;
            f[cnt] = f[now] | t[v].state;
        }
        ++now;
    }
    return;
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
    {
        scanf("%s", s + 1);
        Insert(1 << i - 1);
    }
    Build();
    Solve();
    while (top) putchar(ans[top--]);
    return 0;
}

原文地址:https://www.cnblogs.com/kcn999/p/11385554.html

时间: 2024-08-04 11:55:14

【题解】最短母串的相关文章

BZOJ 1195: [HNOI2006]最短母串

1195: [HNOI2006]最短母串 Time Limit: 10 Sec  Memory Limit: 32 MBSubmit: 1346  Solved: 450[Submit][Status][Discuss] Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12),表示给定的字符串的个数.以下的n行,每行有一个全由大写字母组成的字符串.每个字符串

[BZOJ1195]最短母串

1195: [HNOI2006]最短母串 Time Limit: 10 Sec  Memory Limit: 32 MB Description 给定n个字符串(S1,S2,?,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,?,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12),表示给定的字符串的个数.以下的n行,每行有一个全由大写字母组成的字符串.每个字符串的长度不超过50. Output 只有一行,为找到的最短的字符串T.在保证最短的前提下,如果有多个字

2782: [HNOI2006]最短母串

2782: [HNOI2006]最短母串 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 3  Solved: 2[Submit][Status][Web Board] Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12),表示给定的字符串的个数.以下的n行,每行有一个全由大写字母组成的字符串.每个字符串的长度

bzoj 1195: [HNOI2006]最短母串 爆搜

1195: [HNOI2006]最短母串 Time Limit: 10 Sec  Memory Limit: 32 MBSubmit: 894  Solved: 288[Submit][Status][Discuss] Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12),表示给定的字符串的个数.以下的n行,每行有一个全由大写字母组成的字符串.每个字符串的

最短母串

Ac_automaton的与状压的结合. 看题解说是Ac_automaton上的dp,但是实际上没有十分明显的转移过程,仅仅使用状压的方式记录某个串是否被选择过了(当然有建完Ac_automation然后跑纯状压dp的解法). 首先建立Ac_automaton(Trie图),额外维护一个sta数组,该数组为一个二进制表示数组,‘1’表示该串出现过,‘0’表示该串为出现过.这个信息需要在insert与generate(build)过程中统计,然而有趣的是,网上的大部分题解仅有由fail更新当前节点

Bzoj1195 [HNOI2006]最短母串 [AC自动机]

Time Limit: 10 Sec  Memory Limit: 32 MBSubmit: 1304  Solved: 439 Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12),表示给定的字符串的个数.以下的n行,每行有一个全由大写字母组成的字符串.每个字符串的长度不超过50. Output 只有一行,为找到的最短的字符串T.在保证最短的前提下,如果

python 字符串函数find功能拓展——查找母串内所有子串的位置

前言 我们知道,字符串内置了很多功能的处理函数,其中,find.index函数都可以接受一个参数意义是作为目标子串,而返回母串中从左到右遍历时子串第一次出现的索引值(每一次调用都是从头开始,没有记忆),如果查询不到返回-1. 如下面的例子: 如果,子串不在母串中出现,则find函数返回-1,而index方法返回ValueError错误,这也是两者的区别,接上例: 深入 rindex rfind函数:功能类似,把母串从右向左遍历,找到子串第一次出现的位置,也没有记忆性. 后续 我编写了一个函数,实

luogu题解P1032字串变换--BFS+STL:string骚操作

题目链接 https://www.luogu.org/problemnew/show/P1032 分析 这题本来很裸的一个BFS,发现其中的字符串操作好烦啊.然后就翻大佬题解发现用STL中的string居然变得这么简洁!!! 各种string操作请看另一位大佬博客,写得很全啊: https://www.cnblogs.com/rvalue/p/7327293.html#commentform 其实我们这题只用到两个相关函数:\(S.find(string,pos)\)和\(S.substr()\

dp-LCS(递归输出最短合串)

Problem Description The company "21st Century Fruits" has specialized in creating new sorts of fruits by transferring genes from one fruit into the genome of another one. Most times this method doesn't work, but sometimes, in very rare cases, a