Cod sursa(job #2985432)

Utilizator gabriel10tm@gmail.comGabriel Marian [email protected] Data 26 februarie 2023 14:54:30
Problema ADN Scor 70
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 2.47 kb
#include <bits/stdc++.h>
using namespace std;
#if 1
#define cin fin
#define cout fout
ifstream fin("adn.in");
ofstream fout("adn.out");
#endif // 1
const int inf = 1e7;
const int nmx = 18;
const int mskmx = 1 << nmx;
int a[nmx][nmx];
int dp[mskmx][nmx], t[mskmx][nmx];

vector<int> calcPi(string& s) {
    vector<int> pi(s.size());
    int j = 0;
    for (int i = 1; i < s.size(); i++) {
        while (j > 0 && s[i] != s[j])
            j = pi[j - 1];
        if (s[i] == s[j])
            j++;
        pi[i] = j;
    }
    return pi;
}

int _conc(string& s1, string& s2) {
    string c = s2 + s1;
    vector<int> pi = calcPi(c);
    return min(pi[c.size() - 1],(int)s2.size());
}

string concat(string& s1, string& s2) {
    if(s1.find(s2)!=string::npos)
        return s1;
    int r = _conc(s1,s2);
    return s1 + s2.substr(r);
}

int main() {
    int n;
    cin >> n;
    vector<string> vs(n);
    for (int i = 0; i < n; i++)
        cin >> vs[i];
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            a[i][j] = concat(vs[i],vs[j]).size() - vs[i].size();
    for (int msk = 0; msk < mskmx; msk++)
        for (int i = 0; i < n; i++)
            dp[msk][i] = inf,t[msk][i] = -1;
    // calculate expo dp
    for (int i = 0; i < n; i++)
        dp[1 << i][i] = vs[i].size();
    int mskn = (1 << n);
    for (int msk = 0; msk < mskn; msk++) {
        for (int i = 0; i < n; i++) {
            if (msk & (1 << i)) {
                for (int j = 0; j < n; j++) {
                    if (msk & (1 << j)) {
                        int nv = dp[msk ^ (1 << i)][j] + a[j][i];
                        if (dp[msk][i] > nv) {
                            dp[msk][i] = nv;
                            t[msk][i] = j;
                        }
                    }
                }
            }
        }
    }
    // get minimum
    int mn = INT_MAX, mni;
    for (int i = 0; i < n; i++) {
        if (mn > dp[mskn - 1][i]) {
            mn = dp[mskn - 1][i];
            mni = i;
        }
    }
    // reconstruct path
    int cmsk = mskn - 1;
    int it = mni;
    vector<int> p;
    while (cmsk) {
        p.push_back(it);
        int ta = t[cmsk][it];
        cmsk = cmsk ^ (1 << it);
        it = ta;
    }
//    for(int i=p.size()-1;i>=0;i--)
//        cout << p[i] << " ";
    string res = vs[p.back()];
    for (int i = p.size() - 2; i >= 0; i--)
        res = concat(res, vs[p[i]]);

    cout << res;
}