[BZOJ1195] [HNOI2006]最短母串

Description

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

Input

第一行是一个正整数n(n<=12),表示给定的字符串的个数。
以下的n行,每行有一个全由大写字母组成的字符串。每个字符串的长度不超过50.

Output

只有一行,为找到的最短的字符串T。在保证最短的前提下,
如果有多个字符串都满足要求,那么必须输出按字典序排列的第一个。

Sample Input

2
ABCD
BCDABC

Sample Output

ABCDABC
 
 

 
我对着一个不满足最优子结构的Dp调了1个多小时,重点是竟然骗了80分哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈。
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
#define reg register

int n;
string str[15];
int len[15];
int bin[14];
string f[13][1<<12];
string ans;

int main()
{
    bin[0] = 1;
    for (reg int i = 1 ; i <= 12 ; i ++) bin[i] = bin[i - 1] << 1;
    scanf("%d", &n);
    for (reg int i = 1 ; i <= n ; i ++) cin >> str[i], len[i] = str[i].length();
    for (reg int i = 1 ; i <= n ; i ++) f[i][bin[i - 1]] = str[i];
//    for (reg int i = 1 ; i <= n ; i ++)
//    {
//        for (reg int j = 1 ; j <= n ; j ++)
//        {
//            if (i == j) continue;
//            int l1 = len[i], l2 = len[j];
//            for (reg int k = max(l1 - l2 + 1, 0) ; k < l1 ; k ++)
//            {
//                if (str[i][k] != str[j][0]) continue;
//                bool ok = 1;
//                int now = 0;
//                for (reg int d = k ; d < l1 ; d ++)
//                    if (str[i][d] != str[j][now++]) goto Back;
//                comb[i][j] = str[i];
//                for (reg int d = l1 - k ; d < l2 ; d ++) comb[i][j] += str[j][d];
////                cout<<k<<endl;
//                break;
//                Back:;
//            }
////            if (i == 1 and j == 2) system("pause");
//            if (comb[i][j] == "") comb[i][j] = str[i] + str[j];
//        }
//    }
    for (reg int s = 1 ; s <= bin[n] - 1 ; s ++)
    {
        for (reg int i = 1 ; i <= n ; i ++)
        {
            if (f[i][s] == "") continue;
            if (!(s & bin[i - 1])) continue;
            for (reg int j = 1 ; j <= n ; j ++)
            {
                if (s & bin[j - 1]) continue;
                string comb;
                int l1 = f[i][s].length(), l2 = len[j];
                bool Find = 0;
                for (reg int k = 0 ; k < l1 ; k ++)
                {
                    int now = 0;
                    for (reg int d = k ; d < l1 and now < l2 ; d ++)
                        if (f[i][s][d] != str[j][now++]) goto End;
                    for (reg int d = l1 - k ; d < l2 ; d ++) comb += str[j][d];
                    Find = 1;
                    break;
                    End:;
                }
                if (!Find) comb = str[j];
                if (f[j][s | bin[j - 1]] == "" or f[j][s | bin[j - 1]] > f[i][s] + comb) f[j][s | bin[j - 1]] = f[i][s] + comb;
            }
        }
    }
//    cout<<f[3][bin[n]-1]<<endl;
//    cout<<f[2][bin[n]-1]<<endl;
//    cout << (f[4][bin[n]-1] < f[2][bin[n]-1]) << endl;
    ans = f[1][bin[n] - 1];
    for (reg int i = 2 ; i <= n ; i ++)
    {
        if (ans.length() > f[i][bin[n] - 1].length()) ans = f[i][bin[n] - 1];
        else if (ans.length() == f[i][bin[n] - 1].length()) ans = min(ans, f[i][bin[n] - 1]);
    }
    cout << ans << endl;
    return 0;
}
一个瞎yy的奇形怪状的Dp

其实正解是AC自动机加状压DP。

然后不知道为什么写萎了还只有80分,剩下的都RE了,不管了不想调了。

 


 

 

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <queue>
using namespace std;
#define reg register

int n;
char str[15][550];
int bin[14];
string ans;
char ch[6005];

int nxt[6005][27], tot;
int sit[6005], fail[6005];

inline void Insert(char *s, int id)
{
    int now = 0;
    int len = strlen(s + 1);
    for (reg int i = 1 ; i <= len ; i ++)
    {
        if (nxt[now][s[i] - 'A']) now = nxt[now][s[i] - 'A'];
        else now = nxt[now][s[i] - 'A'] = ++tot, ch[now] = s[i];
    }
    sit[now] |= bin[id - 1];
}

inline void AC_Match()
{
    queue <int> q;
    for (reg int i = 0 ; i < 26 ; i ++) if (nxt[0][i]) q.push(nxt[0][i]);
    while(!q.empty())
    {
        int x = q.front();q.pop();
        for (reg int i = 0 ; i < 26 ; i ++)
        {
            if (nxt[x][i]) fail[nxt[x][i]] = nxt[fail[x]][i], q.push(nxt[x][i]), sit[nxt[x][i]] |= sit[x] | sit[fail[nxt[x][i]]];
            else nxt[x][i] = nxt[fail[x]][i];
        }
    }
}

struct node {
    int point, situ, now;
};
bool vis[605][1<<12];
int pre[60005], top, road[60005];

inline void print(int x)
{
    if (!x) return;
    print(pre[x]);
    putchar(road[x] + 'A');
}

inline void bfs()
{
    queue <node> q;
    int nn = 0;
    q.push((node){0, sit[0], 0});
    vis[0][sit[0]] = 1;
    while(!q.empty())
    {
        int x = q.front().point, situ = q.front().situ, id = q.front().now;
        q.pop();
        if (situ == bin[n] - 1) {
            print(id);
            return ;
        }
        for (reg int i = 0 ; i < 26 ; i ++)
        {
            int nt = situ | sit[nxt[x][i]];
            if (!nxt[x][i]) continue;
            if (vis[nxt[x][i]][nt]) continue;
            vis[nxt[x][i]][nt] = 1;
            pre[++nn] = id, road[nn] = i;
            q.push((node){nxt[x][i], nt, nn});
        }
    }
}

int main()
{
    bin[0] = 1;
    for (reg int i = 1 ; i <= 12 ; i ++) bin[i] = bin[i - 1] << 1;
    scanf("%d", &n);
    for (reg int i = 1 ; i <= n ; i ++) scanf("%s", str[i] + 1), Insert(str[i], i);
    AC_Match();
    bfs();
    return 0;
}

 

posted @ 2018-10-02 15:06  zZhBr  阅读(157)  评论(0编辑  收藏  举报