Cod sursa(job #629043)

Utilizator nandoLicker Nandor nando Data 2 noiembrie 2011 16:37:14
Problema ADN Scor 50
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.38 kb
#include <cstdio>
#include <bitset>
#include <cstring>
#include <iostream>
using namespace std;

FILE* fin = fopen("adn.in", "r");

int n, mask;
const int maxn = 20, maxs = 30010, inf = 0x3f3f3f3f;
bitset<maxn> ban;
char dna[maxn][maxs];
int d[maxn][maxn], c[1 << maxn][maxn], last[1 << maxn][maxn], pi[maxs], len[maxn];

int kmp(int a)
{
    pi[1] = 0;
    for (int q = 2, k = 0; q <= len[a]; ++q) {
        while (k && dna[a][k + 1] != dna[a][q]) {
            k = pi[k];
        }

        if (dna[a][k + 1] == dna[a][q]) {
            ++k;
        }

        pi[q] = k;
    }

    for (int b = 0; b < n; ++b) {
        if (a == b) {
            continue;
        }

        int k = 0;
        bool include = false;
        for (int i = 1; !include && i <= len[b]; ++i) {
            while (k && dna[a][k + 1] != dna[b][i]) {
                k = pi[k];
            }

            if (dna[a][k + 1] == dna[b][i]) {
                ++k;
            }

            if (k == len[a]) {
                include = true;
                break;
            }
        }

        if (include) {
            d[b][a] = -1;
            ban[a] = true;
            mask &= ((1 << n) - 1 - (1 << a));
        } else {
            d[b][a] = k;
        }
    }
}

void recover(int i, int j)
{
    if (i) {
        int prec = last[i][j];

        recover(i ^ (1 << j), prec);
        cout << dna[j] + 1 + d[prec][j];
    }
}

int main()
{
    fscanf (fin, "%d\n", &n);
    freopen("adn.out", "w", stdout);
    mask = (1 << n) - 1;

    for (int i = 0; i < n; ++i) {
        fscanf (fin, "%s\n", dna[i] + 1);
        len[i] = strlen(dna[i] + 1);
    }

    for (int i = 0; i < n; ++i) {
        kmp(i);
    }

    for (int i = 0; i < (1 << n); ++i) {
        for (int j = 0; j < n; ++j) {
            if (!ban[j] && i & (1 << j)) {
                for (int k = 0; k < n; ++k) {
                    if (k != j && !ban[k] && i & (1 << k)) {
                        int cost = c[i ^ (1 << j)][k] + d[k][j];

                        if (c[i][j] <= cost) {
                            c[i][j] = cost;
                            last[i][j] = k;
                        }
                    }
                }
            }
        }
    }

    int lst = 0;
    for (int i = 0; i < n; ++i) {
        if (c[mask][lst] <= c[mask][i]) {
            lst = i;
        }
    }

    recover(mask, lst);
    cout << endl;

    fclose(fin);
    return 0;
}