Cod sursa(job #2764703)

Utilizator DragosC1Dragos DragosC1 Data 22 iulie 2021 11:38:05
Problema ADN Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 5.1 kb
#include <fstream>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
 
char s[20][30005];
int n;
 
vector<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[20];
int tabel[30005];
 
int cost[(1 << 20)][20];
int pre[(1 << 20)][20];
int comun[20][20];
 
vector<int> reconst;
 
const int Inf = 1e9;

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]) {
            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);
                comun[i][j] = ind1;
            }
    
    for (i = 0; i < (1 << n); i++)
        for (j = 1; j <= n; j++)
            cost[i][j] = -Inf;
    
    for (i = 1; i <= n; i++)
        cost[(1 << (i - 1))][i] = 0;

    // cel mai mare lant hamiltonian (dinamica pe stari exponentiale)
    int new_mask, Max, last;
    for (i = 0; i < (1 << n); i++)
        for (j = 1; j <= n; j++)
            if (i & (1 << (j - 1)))
                for (int x: a[j]) 
                    if (!(i & (1 << (x - 1)))) {
                        new_mask = i + (1 << (x - 1));
                        if (cost[new_mask][x] < cost[i][j] + comun[j][x]) {
                            cost[new_mask][x] = max(cost[new_mask][x], cost[i][j] + comun[j][x]);
                            pre[new_mask][x] = j;
                        }
                        if (cost[new_mask][x] >= Max) {
                            Max = cost[new_mask][x];
                            last = x;
                        }
                    }
                    
    // reconstituire
    if (n == 1)
        reconst.push_back(n);
    else {
        int mask, node, nr;
        reconst.emplace_back(last);
        mask = (1 << n) - 1;
        if (n >= 2)
            while (true) {
                node = pre[mask][last];
                reconst.push_back(node);
                mask = mask - (1 << (last - 1));
                last = node;
                nr = 0;
                for (i = 1; i <= n; i++)
                    if (mask & (1 << (i - 1)))
                        nr++;
                if (nr == 1)
                    break;
            }
    }
 
    // afisez rezultatul
    int lung;
    ofstream g("adn.out");
    for (i = reconst.size() - 1; i >= 1; i--) {
        lung = strlen(s[reconst[i]]);
        for (j = 0; j < lung - comun[reconst[i]][reconst[i - 1]]; j++)
            g << s[reconst[i]][j];
    }
    g << s[reconst[0]];
    g.close();
}
 
 
int main() {
    read();
    solve();
    return 0;
}