Cod sursa(job #2962637)

Utilizator AntoniaPopoviciAntonia-Adelina Popovici AntoniaPopovici Data 8 ianuarie 2023 21:59:40
Problema ADN Scor 60
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 2.78 kb
// COMPLEXITATE TIMP: O(n*3^n)
// primul, al doilea, al treilea loop (de la 0 la n-1) = O(n)
// al patrulea loop = O(3^n)
// al cincilea, al saselea loop = O(n)

#include <fstream>
#include <cstring>
using namespace std;

ifstream fin("adn.in");
ofstream fout("adn.out");

const int N = 20, M = 1 << 19, L = 90005, INF = 0x3f3f3f3f;
char s[N][L], aux[L];
int a[N][M], sursa[N][M], start[N][N], p[L], bun[L], lungime[N], n;


int prefix(char a[], char b[])
{
    memset(p, 0, sizeof(p));
    memset(aux, '\0', sizeof(aux));
    strcpy(aux + 1, a + 1);
    strcat(aux + 1, "*");
    strcat(aux + 1, b + 1);
    p[0] = -1;
    for (int i = 2; aux[i]; i++)
        for (int j = p[i - 1]; j >= 0; j = p[j])
            if (aux[j + 1] == aux[i])
            {
                p[i] = j + 1;
                break;
            }
    return p[strlen(aux + 1)];
}

bool verif_string(char a[], char b[])
{
    memset(p, 0, sizeof(p));
    memset(bun, 0, sizeof(bun));
    p[0] = -1;
    for (int i = 2; a[i]; i++)
        for (int j = p[i - 1]; j >= 0; j = p[j])
            if (a[j + 1] == a[i])
            {
                p[i] = j + 1;
                break;
            }
    int n = strlen(a + 1);
    for (int i = 1; b[i]; i++)
        for (int j = bun[i - 1]; j >= 0; j = p[j])
            if (a[j + 1] == b[i])
            {
                bun[i] = j + 1;
                if (bun[i] == n)
                    return true;
                break;
            }
    return false;
}

void update(int& x, int val, int& sursa, int a)
{
    if (x <= val)
        return;
    x = val;
    sursa = a;
}

void afisare(int x, int cheie)
{
    if (cheie == 1 << x)
    {
        fout << s[x] + 1;
        return;
    }
    afisare(sursa[x][cheie], cheie ^ (1 << x));
    fout << s[x] + lungime[x] - start[x][sursa[x][cheie]] + 1;
}

int main()
{
    fin >> n;
    for (int i = 0; i < n; i++)
    {
        fin >> s[i] + 1;
        lungime[i] = strlen(s[i] + 1);
    }
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
        {
            if (verif_string(s[i], s[j]))
                continue;
            start[i][j] = lungime[i] - prefix(s[i], s[j]);
        }
    memset(a, INF, sizeof(a));
    for (int i = 0; i < n; i++)
        a[i][1 << i] = lungime[i];
    for (int j = 1; j < 1 << n; j++)
        for (int i = 0; i < n; i++)
            for (int k = 0; k < n; k++)
                if ((j & (1 << i)) && (j & (1 << k)) == 0)
                    update(a[k][j | (1 << k)], a[i][j] + start[k][i], sursa[k][j | (1 << k)], i);
    int cheie = (1 << n) - 1, cmb = 0;
    for (int i = 0; i < n; i++)
        if (a[i][cheie] < a[cmb][cheie])
            cmb = i;
    afisare(cmb, cheie);
    fout << "\n";
    return 0;
}