Cod sursa(job #2058611)

Utilizator retrogradLucian Bicsi retrograd Data 5 noiembrie 2017 21:54:23
Problema ADN Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.53 kb
#include <fstream>
#include <vector>

using namespace std;

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

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

vector<string> Prune(vector<string> strs) {
    vector<string> ret;
    for (auto s : strs) {
        auto pi = GetPi(s);

        bool match = false;
        for (auto t : strs) {
            if (t == s) continue;

            int j = 0;
            for (auto c : t) {
                while (j != -1 && s[j] != c)
                    j = pi[j];

                j += 1;
                if (j == (int)s.size()) { 
                    match = true; 
                    break; 
                }
            }
            if (match) break;
        }

        if (!match) ret.push_back(s);
    }
    return ret;
}

int ComputeMid(string a, string b) {
    auto pi = GetPi(b);
    int j = 0;
    for (auto c : a) {
        while (j != -1 && b[j] != c)
            j = pi[j];
        j += 1;
    }
    return j;
}

int DP[1 << 18][18], Par[1 << 18][18];
int Mid[18][18];
vector<string> strs;

void Output(int c, int last) {
    if (c == (1 << last)) cout << strs[last];
    else {
        Output(c ^ (1 << last), Par[c][last]);
        int mid = Mid[Par[c][last]][last];
        cout << strs[last].substr(mid);
    }
}

int main() {
    
    int n; cin >> n;
    strs.resize(n);
    for (int i = 0; i < n; ++i)
        cin >> strs[i];
    strs = Prune(move(strs));
    n = strs.size();

    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j)
            Mid[i][j] = ComputeMid(strs[i], strs[j]);

    for (int c = 0; c < (1 << n); ++c) {
        for (int i = 0; i < n; ++i) {
            if (!(c & (1 << i))) continue;
            if (c == (1 << i)) DP[c][i] = strs[i].size();
            else {
                DP[c][i] = 1e9;
                for (int j = 0; j < n; ++j) {
                    if (!(c & (1 << j)) or i == j) continue;
                    
                    int now = DP[c ^ (1 << i)][j] + strs[i].size() - Mid[j][i];
                    if (DP[c][i] > now) {
                        DP[c][i] = now;
                        Par[c][i] = j;
                    }
                }
            }
        }
    }
    
    int last = 0, c = ((1 << n) - 1);
    for (int i = 0; i < n; ++i)
        if (DP[c][i] < DP[c][last])
            last = i;

    Output(c, last); cout << endl;

    return 0;
}