Cod sursa(job #2962723)

Utilizator lucianul31Moisii Lucian lucianul31 Data 8 ianuarie 2023 23:35:43
Problema ADN Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.33 kb
#include <fstream>
#include <vector>
#include <string>
#include <string.h>
#include <algorithm>

using namespace std;

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

const int NMAX = 19, MMAX = 30005, INF = 2e9;
char s[NMAX][MMAX];
int N, dp[(1 << NMAX)][NMAX], Lengths[NMAX], p[MMAX], Father[(1 << NMAX)][NMAX], Cost[NMAX][NMAX], f[NMAX];
vector<pair<int, int>> Edges[NMAX];
vector<int> v;

int main()
{

    in >> N;

    for (int i = 1; i <= N; i++)
    {
        in >> s[i] + 1;
        Lengths[i] = strlen(s[i] + 1);
    }
    for (int i = 1; i <= N; i++)
    {
        memset(p, 0, sizeof(p));
        int l = 0;
        for (int j = 2; j <= Lengths[i]; j++)
        {
            while (l && s[i][j] != s[i][l + 1])
                l = p[l];
            if (s[i][j] == s[i][l + 1])
                l++;
            p[j] = l;
        }
        for (int j = 1; j <= N; j++)
        {
            if (i == j)
                continue;
            int l = 0, ok = 0;
            for (int k = 1; k <= Lengths[j]; k++)
            {
                while (l && s[j][k] != s[i][l + 1])
                    l = p[l];
                if (s[j][k] == s[i][l + 1])
                    l++;
                if (l == Lengths[i])
                {
                    ok = 1;
                    break;
                }
            }
            if (ok)
            {

                Edges[i - 1].push_back({j - 1, 0});
                f[i] = 1;
                Cost[j - 1][i - 1] = 0;
            }
            else
            {
                Edges[i - 1].push_back({j - 1, Lengths[i] - l});
                Cost[j - 1][i - 1] = Lengths[i] - l;
            }
        }
    }
    int M = (1 << N);
    for (int i = 0; i < M; i++)
        for (int j = 0; j < N; j++)
            dp[i][j] = INF;

    int FinalMask = 0;

    for (int i = 0; i < N; i++)

        if (!f[i + 1])
        {
            dp[(1 << i)][i] = Lengths[i + 1];
            FinalMask += (1 << i);
        }

    for (int state = 1; state <= FinalMask; state++)
    {
        for (int i = 0; i < N; i++)
        {
            if (!(state & (1 << i)) || f[i + 1])
                continue;
            for (auto it : Edges[i])
            {
                int vecin = it.first, cost = it.second;
                if (!(state & (1 << vecin)) || f[vecin + 1])
                    continue;
                if (dp[state - (1 << i)][vecin] + cost < dp[state][i])
                {
                    dp[state][i] = dp[state - (1 << i)][vecin] + cost;
                    Father[state][i] = vecin;
                }
            }
        }
    }

    int sol = INF, last = 0;

    for (int i = 0; i < N; i++)
        if (!f[i + 1] && dp[FinalMask][i] < sol)
        {
            sol = dp[FinalMask][i];

            last = i;
        }
    int x = FinalMask, y = last;
    v.push_back(y);
    while (x)
    {
        int aux = (1 << y);
        y = Father[x][y];
        x -= aux;
        v.push_back(y);
    }
    v.pop_back();
    reverse(v.begin(), v.end());
    out << s[v[0] + 1] + 1;
    for (int i = 1; i < v.size(); i++)
    {
        int idx = v[i] + 1, val = Cost[v[i - 1]][v[i]];
        for (int j = Lengths[idx] - val + 1; j <= Lengths[idx]; j++)
            out << s[idx][j];
    }
    return 0;
}