zoukankan      html  css  js  c++  java
  • [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;
    }
  • 相关阅读:
    Kinect学习笔记(六)——深度数据测量技术及应用
    [device]/proc/devices and /dev/
    [Eth]Mac/Phy/mdio/Rgmii
    [uboot]uboot如何引导系统
    [网络]Linux一些网络知识
    [基础]sizeof和strlen
    [基础]关于extern指针和数组的用法
    [ucos]了解ucos
    [Linux]gcc/libc/glibc
    [i.MX6q]i.MX6q处理器,linux操作系统平台搭建 从SD卡启动系统
  • 原文地址:https://www.cnblogs.com/BriMon/p/9737156.html
Copyright © 2011-2022 走看看