Cod sursa(job #2964408)

Utilizator Ruxi_GontescuGontescu Maria Ruxandra Ruxi_Gontescu Data 12 ianuarie 2023 22:11:03
Problema ADN Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.53 kb
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <map>

using namespace std;

const int INF = (1 << 30);

vector <int> kmp(string s, string t) {
    string w = s + "$" + t;
    vector <int> pi(w.size(), 0);
    for (int i = 1, k = 0; i < w.size(); ++i) {
        while (k > 0 && w[i] != w[k])
            k = pi[k - 1];
        if (w[i] == w[k])
            ++k;
        pi[i] = k;
    }
    return pi;
}

bool isSubstring(string s, string t) {
    vector <int> pi = kmp(s, t);
    return find(pi.begin(), pi.end(), s.size()) != pi.end();
}

int main() {
    ifstream fin("adn.in");
    ofstream fout("adn.out");
    int N;
    fin >> N;
    vector <string> input_words(N);
    for (int i = 0; i < N; ++i) {
        fin >> input_words[i];
    }
    // remove duplicates
    vector <string> words;
    sort(input_words.begin(), input_words.end());
    for (int i = 0, j = 0; i < input_words.size(); i = j) {
        while (j < input_words.size() && input_words[i] == input_words[j]) {
            ++j;
        }
        words.push_back(input_words[i]);
    }
    input_words = words;
    words.clear();
    //remove useless words (words that are substrings of other words)
    N = input_words.size();
    for (int i = 0; i < N; ++i) {
        bool ok = true;
        for (int j = 0; j < N && ok; ++j) {
            if (i != j && isSubstring(input_words[i], input_words[j])) {
                ok = false;
            }
        }
        if (ok) {
            words.push_back(input_words[i]);
        }
    }
    /*for (auto& i : words) {
        cerr << i << "\n";
    }*/
    N = words.size();
    vector <vector <int>> cost(N, vector <int>(N, 0));
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            if (i != j) {
                cost[i][j] = kmp(words[i], words[j]).back();
            }
        }
    }
    vector <vector <int>> dp(N, vector <int>((1 << N), -INF));
    vector <vector <pair <int, int>>> prev(N, vector <pair <int, int>>((1 << N)));
    for (int i = 0; i < N; ++i) {
        dp[i][1 << i] = 0;
        prev[i][1 << i] = { -1, 0 };
    }
    for (int mask = 1; mask < (1 << N); ++mask) {
        for (int i = 0; i < N; ++i) {
            if (mask & (1 << i)) {
                for (int j = 0; j < N; ++j) {
                    if (!(mask & (1 << j))) {
                        int new_mask = mask | (1 << j);
                        if (dp[i][mask] + cost[j][i] > dp[j][new_mask]) {
                            dp[j][new_mask] = dp[i][mask] + cost[j][i];
                            prev[j][new_mask] = { i, mask };
                        }
                    }
                }
            }
        }
    }
    int best = -INF;
    int pos = -1;
    for (int i = 0; i < N; ++i) {
        if (dp[i][(1 << N) - 1] > best) {
            best = dp[i][(1 << N) - 1];
            pos = i;
        }
    }
    vector <int> words_order;
    int mask = (1 << N) - 1;
    while (pos != -1) {
        //cerr << pos << " " << mask << "\n";
        words_order.push_back(pos);
        int new_pos = prev[pos][mask].first;
        mask = prev[pos][mask].second;
        pos = new_pos;
    }
    reverse(words_order.begin(), words_order.end());
    /*for (auto& i : words_order) {
        cerr << words[i] << "\n";
    }*/
    string answer = words[words_order[0]];
    for (int i = 1; i < N; ++i) {
        int c = cost[words_order[i]][words_order[i - 1]];
        /*cerr << c << "\n";*/
        answer += words[words_order[i]].substr(c);
    }
    fout << answer << "\n";
    fin.close();
    fout.close();
    return 0;
}