Cod sursa(job #2939063)

Utilizator cberindeCodrin Berinde cberinde Data 12 noiembrie 2022 22:06:43
Problema ADN Scor 0
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.4 kb
#include <bits/stdc++.h>
using namespace std;
ifstream fin("adn.in");
ofstream fout("adn.out");

int N;
string s[19];
int dist[19][19];
long long dp[19][524289];
int parinte[19][524289];

bool kmp(int a1, int a2) {
    string V = '0' + s[a1] + '*' + s[a2];
    int n = V.size() - 1;
    int nz = s[a1].size();
    int pi[60004];
    for(int i = 2; i <= n; i++) {
        if(V[i] == V[pi[i - 1] + 1]) {
            pi[i] = pi[i - 1] + 1;
        }
        else {
            int j = pi[pi[i - 1]];
            while(j > 0 && V[i] != V[j + 1]) {
                j = pi[j];
            }
            if(V[i] == V[j + 1]) {
                pi[i] = j + 1;
            }
            else {
                if(V[i] == V[1])
                    pi[i] = 1;
                else
                    pi[i] = 0;
            }
        }
        if(pi[i] == nz && i > nz) {
            return true;
        }
    }
    return false;
}

void citire() {
    fin >> N;
    for(int i = 1; i <= N; i++) {
        fin >> s[i];
        for(int j = 1; j < i; j++) {
            if(kmp(j, i)) {
                for(int k = j; k < i; k++) {
                    s[k] = s[k+1];
                }
                i--;
                N--;
            }
            if(kmp(i, j)) {
                i--;
                N--;
            }

        }
    }
}

int pi[60005];

int calc_dist(int s1, int s2) {
    string A = '0' + s[s1] + '*' + s[s2];
    int n = A.size() - 1;

    for(int i = 0; i <= n; i++) {
        pi[i] = 0;
    }

    //incepe kmp
    for(int i = 2; i <= n; i++) {
        if(A[i] == A[pi[i - 1] + 1]) {
            pi[i] = pi[i - 1] + 1;
        }
        else {
            int j = pi[pi[i - 1]];
            while(j > 0 && A[i] != A[j + 1]) {
                j = pi[j];
            }
            if(A[i] == A[j + 1]) {
                pi[i] = j + 1;
            }
            else {
                if(A[i] == A[1])
                    pi[i] = 1;
                else
                    pi[i] = 0;
            }
        }
    }
    return pi[n];
}

void init() {
    for(int sir1 = 1; sir1 <= N; sir1++) {
        for(int sir2 = 1; sir2 <= N; sir2++) {
            if(sir1 != sir2) {
                //se calculeaza distanta intre stringuri
                dist[sir1][sir2] = calc_dist(sir2, sir1);
            }
        }
    }

    //initializam matricea de parinti
    for(int i = 1; i <= N; i++) {
        parinte[i][0] = -1;
    }
}

void cautare() {
    //parcurgem dp pe configuratii
    int stop = (1 << N) - 1;
    for(int i = 1; i <= stop; i++) {
        //ne ducem in toate dp-urile nodurilor in care i are 1 pe pozitia corespunzatoare lui
        int config = i;
        for(int nod = 1; nod <= N; nod++) {
            if((config & (1 << (nod - 1))) != 0) { //avem 1 pe pozitia nodului

                config = config & (~(1 << (nod - 1)));//stergem 1 de pe pozitia nodului

                int mx = -1, orig;
                for(int y = 1; y <= N; y++) {
                    if(y != nod && (dp[y][config] + dist[y][nod] > mx)) {
                        mx = dp[y][config] + dist[y][nod];
                        orig = y;
                    }
                }
                dp[nod][i] = mx;
                parinte[nod][i] = orig;
            }
            config = i;
        }
    }
}

int ultimul() {//rezultatul este stocat in maximul coresp ultimei coloane
    int coloana = (1 << N) - 1;
    int rez = 0, nod;
    for(int i = 1; i <= N; i++) {
        if(dp[i][coloana] > rez) {
            rez = dp[i][coloana];
            nod = i;
        }
    }
    return nod;
}

string secventa = "";

void concat(int indice, int suprap) {
    int y = secventa.size() - suprap;
    int stop = y + s[indice].size() - 1;
    for(int i = y; i <= stop; i++) {
        if(i >= secventa.size())
            secventa += s[indice][i - y];
        else
            secventa[i] = s[indice][i - y];
    }
}

void calculare(int nod, int config) {
    bitset<22> b(config);
    int p = parinte[nod][config];
    if(b.count() > 1)
        calculare(p, (config) & ~(1 << (nod - 1)));
    if(secventa == "") {
        secventa = s[nod];
    }
    else {
        concat(nod, dist[p][nod]);
    }
}

int main() {
    citire();
    init();
    cautare();
    calculare(ultimul(), (1 << N) - 1);
    fout << secventa;
    return 0;
}