Cod sursa(job #2151373)

Utilizator FrequeAlex Iordachescu Freque Data 4 martie 2018 13:38:31
Problema ADN Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.41 kb
#include <bits/stdc++.h>

using namespace std;

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

const int NMAX = 18 + 5;
const int PMAX = (1 << 18) + 5;
const int LMAX = 30001 + 5;
const int INF = 0x3f3f3f3f;

vector <int> v;
int n;
int len[NMAX], phi[NMAX];
char lant[NMAX][LMAX];
bool useless[NMAX];
int comun[NMAX][NMAX];
int dp[NMAX][PMAX];
int prv[NMAX][PMAX]; /// indicele sirului pus inaintea ultimului

void prefix(int node)
{
    for (int i = 2; i <= len[node]; ++i)
    {
        int last = phi[i - 1];
        while (last > 0 && lant[node][i] != lant[node][last + 1]) last = phi[last];
        if (lant[node][i] == lant[node][last + 1]) phi[i] = last + 1;
    }
}

bool kmp (int pref, int node)
{
    int k = 0;
    for (int i = 1; i <= len[pref]; ++i)
    {
        while (k > 0 && lant[pref][i] != lant[node][k + 1]) k = phi[k];
        if (lant[pref][i] == lant[node][k + 1]) ++k;

        if (k == len[node])
        {
            comun[pref][node] = len[node];
            return true;
        }
    }
    comun[pref][node] = k;
    return false;
}

void read()
{
    fin >> n;
    for (int i = 1; i <= n; ++i)
    {
        fin >> (lant[i] + 1);
        len[i] = strlen(lant[i] + 1);
    }
}

void Copiaza(char* A, string& ans, int x, int y, int w, int z)
{
    int lung = z - w + 1;
    for (int i = 0; i < lung; i++)
        ans[w + i] = A[x + i];
}

string Reconst(int index)
{
    int conf = (1 << n) - 1;
    string ans;
    ans.resize(dp[conf][index]);
    int lung = dp[conf][index] - 1;
    while (conf > 0)
    {
        /// pun pe index
        int comun_prv = 0;
        int nxt = v[prv[conf][index]];
        int aux = conf - (1 << index);
        if (aux != 0)
            comun_prv = comun[nxt][v[index]];

        Copiaza(lant[v[index]], ans, comun_prv + 1, len[v[index]], lung - (len[v[index]] - comun_prv) + 1, lung);

        lung -= (len[v[index]] - comun_prv);
        index = prv[conf][index];
        conf = aux;
    }

    return ans;
}

int main()
{
    read();
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            if (i != j)
            {
                prefix(j);
                useless[j] = max(useless[j], kmp(i, j));
                //comun[j][i] = lant[j][len[j]];
            }

    for (int i = 1; i <= n; ++i)
        if (!useless[i])
            v.push_back(i);

    n = v.size();

    for (int conf = 1; conf < (1 << n); conf++)
        for (int i = 0; i < n; i++)
            if (conf & (1 << i))
            {
                dp[conf][i] = 1 << 30; /// inf

                int aux = conf - (1 << i);

                if (aux == 0) dp[conf][i] = len[v[i]];
                else for (int j = 0; j < n; j++)
                        if (aux & (1 << j))
                            if (dp[conf][i] > dp[aux][j] + len[v[i]] - comun[v[j]][v[i]])
                            {
                                dp[conf][i] = dp[aux][j] + len[v[i]] - comun[v[j]][v[i]];
                                prv[conf][i] = j;
                            }
            }

    int sol = 1 << 30, ind;
    for (int i = 0; i < n; i++)
        if (sol > dp[(1 << n) - 1][i])
        {
            sol = dp[(1 << n) - 1][i];
            ind = i;
        }
    /// reconstructia lui dp[(1 << n) - 1][ind]
    string str_sol = Reconst(ind);
    fout << str_sol << "\n";

    return 0;
}