Cod sursa(job #2764533)

Utilizator DragosC1Dragos DragosC1 Data 21 iulie 2021 14:04:29
Problema ADN Scor 0
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.88 kb
#include <fstream>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;

char s[19][30001];
int n;

vector<pair<int, int>> a[20];

void read() {
    int i;
    ifstream f("adn.in");
    f >> n;
    for (i = 1; i <= n; i++) 
        f >> s[i];
    f.close();
}

bool eliminat[19];
int tabel[30001];

int cost[(1 << 19)];

vector<int> reconst;

void solve() {
    int i, j, ind1, ind2, lung1, lung2, k, ok;

    // kmp sa elimin sirurile care sunt in alte siruri O(n^2 * (lung1 + lung2))
    for (i = 1; i <= n; i++)
        if (!eliminat[i])
            for (j = 1; j <= n; j++)
                if (i != j && !eliminat[j]) {
                    ind1 = 0, ind2 = 1, lung1 = strlen(s[i]), lung2 = strlen(s[j]);
                    for (k = 0; k < lung1; k++)
                        tabel[k] = 0;
                    while (ind2 < lung1) {
                        if (s[i][ind1] == s[i][ind2]) {
                            tabel[ind2] = ind1 + 1;
                            ind1++, ind2++;
                        }
                        else if (ind1 != 0)
                            ind1 = tabel[ind1 - 1];
                        else ind2++;
                    }
                    ok = 0;
                    ind1 = 0;
                    for (ind2 = 0; ind2 < lung2;) {
                        if (s[i][ind1] == s[j][ind2]) 
                            ind1++, ind2++;
                        else if (ind1 != 0)
                            ind1 = tabel[ind1 - 1];
                        else ind2++;
                        if (ind1 == lung1) {
                            ok = 1;
                            break;
                        }
                    }
                    if (ok)
                        eliminat[i] = 1;
                }
    int l = 0;
    for (i = 1; i <= n; i++)
        if (!eliminat[i]) {
            l++;
            strcpy(s[l], s[i]);
        }
    n = l;

    // asociem cuvintelor un graf ponderat, in care costul reprezinta cel mai lung sufix din i care este prefix in j (tot cu KMP)
    for (i = 1; i <= n; i++)
        for (j = 1; j <= n; j++)
            if (i != j) {
                ind1 = 0, ind2 = 1, lung1 = strlen(s[i]), lung2 = strlen(s[j]);
                for (k = 0; k < lung2; k++)
                    tabel[k] = 0;
                while (ind2 < lung2) {
                    if (s[j][ind1] == s[j][ind2]) {
                        tabel[ind2] = ind1 + 1;
                        ind1++, ind2++;
                    }
                    else if (ind1 != 0)
                        ind1 = tabel[ind1 - 1];
                    else ind2++;
                }
                ind1 = 0;
                for (ind2 = 0; ind2 < lung1; ) {
                    if (s[j][ind1] == s[i][ind2]) 
                        ind1++, ind2++;
                    else if (ind1 != 0)
                        ind1 = tabel[ind1 - 1];
                    else ind2++;
                }
                a[i].push_back({j, ind1});
            }
    
    // cel mai mare lant hamiltonian (dinamica pe stari exponentiale)
    int new_mask;
    for (i = 1; i < (1 << n); i++)
        for (j = 1; j <= n; j++)
            if (i & (1 << (j - 1)))
                for (pair<int, int> x : a[j])
                    if (!(i & (1 << (x.first - 1)))) {
                        new_mask = i + (1 << (x.first - 1));
                        cost[new_mask] = max(cost[new_mask], cost[i] + x.second);
                    }
    
    // reconstituim drumul
    int mask = (1 << n) - 1, cnt, last;
    while (true) {
        ok = 1;
        for (i = 1; i <= n && ok; i++)
            if (mask & (1 << (i - 1)))
                for (pair<int, int> x : a[i]) 
                    if (mask & (1 << (x.first - 1)) && ok) {
                        new_mask = mask - (1 << (x.first - 1));
                        if (cost[new_mask] + x.second == cost[mask]) {
                            mask = new_mask;
                            reconst.push_back(x.first);
                            ok = 0;
                        }
                    }
        cnt = 0;
        for (i = 1; i <= n; i++)
            if (mask & (1 << (i - 1))) {
                cnt++;
                last = i;
            }
        if (cnt == 1)
            break;
    }
    reconst.push_back(last);

    // afisam sirul nou
    int lung, c;
    ofstream g("adn.out");
    for (i = reconst.size() - 1; i >= 1; i--) {
        for (pair<int, int> x : a[reconst[i]]) {
            if (x.first == reconst[i - 1]) {
                c = x.second;
                break;
            }
        }
        lung = strlen(s[reconst[i]]);
        for (j = 0; j < lung - c; j++)
            g << s[reconst[i]][j];
    }
    g << s[reconst[0]];
    g.close();
}


int main() {
    read();
    solve();
    return 0;
}