Cod sursa(job #2603336)

Utilizator AokijiAlex M Aokiji Data 19 aprilie 2020 11:59:06
Problema ADN Scor 60
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.02 kb
#include <iostream>
#include <cstdio>
#include <cstring>
#define NMAX 18
#define LMAX 30000

using namespace std;

int n;
int urm[2 * LMAX + 5];
int d[(1 << NMAX) + 1][NMAX + 1][2];
char s[NMAX + 1][LMAX + 5];
char p[2 * LMAX + 10];

int prefix(char *pattern, int lp)
{
    int k, bestk = 0;

    urm[0] = 0;
    for(int i = 1; i < lp; i++)
    {
        k = urm[i - 1];
        while(k > 0 && pattern[i] != pattern[k])
            k = urm[k - 1];
        if(pattern[i] == pattern[k])
            k++;
        urm[i] = k;
    }
    return urm[lp - 1];
}

void get_adn(int ind, int bm)
{
    if(d[bm][ind][1] == -1)
        printf("%s", s[ind]);
    else
    {
        int old_bm = bm ^ (1 << ind), dad = d[bm][ind][1], old_l = d[old_bm][dad][0], crt_l = d[bm][ind][0], lind = strlen(s[ind]);
        get_adn(dad, old_bm);
        printf("%s", s[ind] + lind - crt_l + old_l);
    }
}

bool inside(int ind1, int ind2)
{
    int l2 = strlen(s[ind2]), l1 = strlen(s[ind1]);
    int aux = prefix(s[ind2], l2), k = 0;
    for(int i = 0; i < l1; i++)
    {
        while(k > 0 && s[ind1][i] != s[ind2][k])
            k = urm[k - 1];
        if(s[ind1][i] == s[ind2][k])
            k++;
        if(k == l2)
            return true;
    }
    return false;
}

void elim(int ind)
{
    for(int i = ind; i < n; i++)
        swap(s[i], s[i + 1]);
    n--;
}

int main()
{
    freopen("adn.in", "r", stdin);
    freopen("adn.out", "w", stdout);
    int pn;
    scanf("%d ", &n);
    for(int i = 0; i < n; i++)
        scanf("%s", &s[i]);
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            if(j != i && inside(i, j)) /// daca j se afla in interiorul lui i
                elim(j--);
    pn = 1 << n;
    for(int bm = 1; bm < pn; bm++)
        for(int i = 0; i < n; i++)
            if(bm & (1 << i))
            {
                int nbm = bm ^ (1 << i), li = strlen(s[i]);
                if(nbm == 0)
                    d[bm][i][0] = li, d[bm][i][1] = -1;
                else
                {
                    strncpy(p, s[i], li);
                    p[li] = '#';
                    for(int j = 0; j < n; j++)
                        if(nbm & (1 << j))
                        {
                            int lj = strlen(s[j]);
                            strncpy(p + li + 1, s[j], lj);
                            p[li + lj + 1] = NULL;
                            int ll = prefix(p, li + lj + 1);
                            if(d[bm][i][0] == 0 || d[nbm][j][0] - ll + li < d[bm][i][0])
                            {
                                d[bm][i][0] = d[nbm][j][0] - ll + li;
                                d[bm][i][1] = j;
                            }
                        }
                }
            }
    int minim = 18 * LMAX + 5, pozmin = 0;
    for(int i = 0; i < n; i++)
        if(d[pn - 1][i][0] != 0 && d[pn - 1][i][0] < minim)
            minim = d[pn - 1][i][0], pozmin = i;
    get_adn(pozmin, pn - 1);
    return 0;
}