Cod sursa(job #2975148)

Utilizator Matei_MunteanuMunteanu Matei Ioan Matei_Munteanu Data 5 februarie 2023 16:26:13
Problema ADN Scor 40
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.6 kb
#include <bits/stdc++.h>
using namespace std;
const int NMAX = 18;
const int SMAX = 30004;
const int INF = 4000004;

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

int n;
bool ok;
vector<string> adn;
vector<string> adn_rau;
int comun[NMAX][NMAX];
int lps[2 * SMAX];
pair<int, int> dp[NMAX][(1 << (NMAX - 1)) + 4];
int p[NMAX][(1 << (NMAX - 1)) + 4];
vector<int> cuv;

int kmp(string a, string b)
{
    string s = b + '#' + a;
    lps[0] = 0;
    for (int i = 1; i < (int)s.size(); i++)
    {
        int j = lps[i - 1];
        while (j > 0 && s[j] != s[i])
        {
            j = lps[j - 1];
        }
        if (s[j] == s[i])
        {
            j++;
        }
        lps[i] = j;
    }
    return lps[s.size() - 1];
}

bool kmp_find(string a, string b)
{
    string s = a + '#' + b;
    lps[0] = 0;
    for (int i = 1; i < (int)s.size(); i++)
    {
        int j = lps[i - 1];
        while (j > 0 && s[j] != s[i])
        {
            j = lps[j - 1];
        }
        if (s[j] == s[i])
        {
            j++;
        }
        lps[i] = j;
    }
    for (int i = (int)a.size() + 1; i < (int)s.size(); i++)
    {
        if (lps[i] == (int)a.size())
        {
            return true;
        }
    }
    return false;
}

int main()
{
    fin >> n;
    for (int i = 0; i < n; i++)
    {
        string s;
        fin >> s;
        adn_rau.push_back(s);
    }
    for (int i = 0; i < n; i++)
    {
        ok = true;
        for (int j = 0; j < n; j++)
        {
            if (i == j)
            {
                continue;
            }
            if (kmp_find(adn_rau[i], adn_rau[j]))
            {
                ok = false;
                break;
            }
        }
        if (ok)
        {
            adn.push_back(adn_rau[i]);
        }
    }
    n = adn.size();
    for (int i = 0; i < n; i++)
    {
        for (int j = i + 1; j < n; j++)
        {
            comun[i][j] = kmp(adn[i], adn[j]);
            comun[j][i] = kmp(adn[j], adn[i]);
        }
    }
    for (int i = 0; i < n; i++)
    {
        for (int conf = 0; conf < (1 << (n - 1)); conf++)
        {
            dp[i][conf] = {INF, INF};
        }
    }
    for (int i = 1; i < n; i++)
    {
        dp[i][(1 << (i - 1))] = {(int)adn[0].size() + (int)adn[i].size() - comun[0][i], comun[0][i]};
        p[i][(1 << (i - 1))] = 0;
    }
    for (int conf = 1; conf < (1 << (n - 1)); conf++)
    {
        for (int i = 1; i < n; i++)
        {
            if (conf & (1 << (i - 1)))
            {
                for (int j = 1; j < n; j++)
                {
                    if (i == j)
                    {
                        continue;
                    }
                    if (conf & (1 << (j - 1)))
                    {
                        if (dp[j][conf].first > (dp[i][conf ^ (1 << (j - 1))].first + (int)adn[j].size() - comun[i][j]))
                        {
                            dp[j][conf].first = dp[i][conf ^ (1 << (j - 1))].first + (int)adn[j].size() - comun[i][j];
                            dp[j][conf].second = min(dp[i][conf ^ (1 << (j - 1))].second, comun[i][j]);
                            p[j][conf] = i;
                        }
                    }
                }
            }
        }
    }
    for (int i = 1; i < n; i++)
    {
        dp[i][(1 << (n - 1)) - 1].first -= comun[i][0];
        dp[i][(1 << (n - 1)) - 1].second = min(dp[i][(1 << (n - 1)) - 1].second, comun[i][0]);
    }
    int ind = 1;
    for (int i = 2; i < n; i++)
    {
        if ((dp[i][(1 << (n - 1)) - 1].first + dp[i][(1 << (n - 1)) - 1].second) < (dp[ind][(1 << (n - 1)) - 1].first + dp[ind][(1 << (n - 1)) - 1].second))
        {
            ind = i;
        }
    }
    int leg_min = dp[ind][(1 << (n - 1)) - 1].second;
    int conf = (1 << (n - 1)) - 1;
    cuv.push_back(0);
    while (ind != 0)
    {
        cuv.push_back(ind);
        int aux = ind;
        ind = p[ind][conf];
        conf = conf ^ (1 << (aux - 1));
    }
    cuv.push_back(0);
    reverse(cuv.begin(), cuv.end());
    int index;
    for (int i = 0; i < (int)cuv.size() - 1; i++)
    {
        if (comun[cuv[i]][cuv[i + 1]] == leg_min)
        {
            index = i + 1;
        }
    }
    int l = (int)cuv.size();
    for (int i = 1; i < l; i++)
    {
        cuv.push_back(cuv[i]);
    }
    fout << adn[cuv[index]];
    for (int i = index + 1; i <= index + l - 2; i++)
    {
        fout << adn[cuv[i]].substr(comun[cuv[i - 1]][cuv[i]], (int)adn[cuv[i]].size() - comun[cuv[i] - 1][cuv[i]]);
    }
    return 0;
}