Cod sursa(job #1580641)

Utilizator EpictetStamatin Cristian Epictet Data 25 ianuarie 2016 23:08:47
Problema ADN Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.76 kb
#include <fstream>
#include <cstring>
#include <string>
#include <vector>

using namespace std;

ifstream fin ("adn.in");
ofstream fout ("adn.out");

int n, D[30010], Cost[20][20], C[20][(1 << 18) + 10], Dad[20][(1 << 18) + 10];
string S[20];
bool F[20];
vector < int > Sol;

int KMP(string &A, string &B)
{
    int k = 0;
    for (int i = 1; i < A.size(); i ++)
    {
        while (k && A[i] != A[k]) k = D[k - 1];
        if (A[i] == A[k]) k ++;
        D[i] = k;
    }

    k = 0;
    for (int i = 0; i < B.size(); i ++)
    {
        while (k && B[i] != A[k]) k = D[k - 1];
        if (B[i] == A[k]) k ++;
    }

    return k;
}

bool Verif(string &A, string &B)
{
    int k = 0;
    for (int i = 1; i < A.size(); i ++)
    {
        while (k && A[i] != A[k]) k = D[k - 1];
        if (A[i] == A[k]) k ++;
        D[i] = k;
    }

    k = 0;
    for (int i = 0; i < B.size(); i ++)
    {
        while (k && B[i] != A[k]) k = D[k - 1];
        if (B[i] == A[k]) k ++;
        if (k == A.size())
        {
            return true;
        }
    }

    return false;
}

int main()
{
    fin >> n;
    for (int i = 1; i <= n; i ++) fin >> S[i];

    /// Daca se cuprinde vreun cuvant in altul
    for (int i = 1; i <= n; i ++)
    {
        for (int j = 1; j <= n; j ++)
        {
            if (i == j || F[i] || F[j]) continue;
            if (S[i].size() <= S[j].size())
            {
                if (Verif(S[i], S[j])) F[i] = true;
            }
        }
    }


    /// Elimin cuvintele cuprinse in altele
    for (int i = 1; i <= n; i ++)
    {
        while (F[i] && i <= n)
        {
            swap(F[i], F[n]);
            swap(S[i], S[n]);
            n --;
        }
    }

    for (int i = 1; i <= n; i ++)
    {
        for (int j = 1; j <= n; j ++)
        {
            if (i == j) continue;
            Cost[i - 1][j - 1] = KMP(S[j], S[i]); /// cel mai lung sufix al cuvantului i care este prefix al cuvantului j
        }
    }

    /*for (int i = 1; i <= n; i ++) fout << S[i] << '\n';

    for (int i = 0; i < n; i ++)
    {
        for (int j = 0; j < n; j ++)
        {
            fout << Cost[i][j] << ' ';
        }
        fout << '\n';
    }*/

    /// ciclu hamiltonian de cost maxim j find nodul de inceput adaugandul de fiecare data
    for (int mask = 0; mask < (1 << n); mask ++)
    {
        for (int j = 0; j < n; j ++)
        {
            Dad[j][mask] = -1;
            if (mask & (1 << j))
            {
                for (int k = 0; k < n; k ++)
                {
                    if (mask & (1 << k))
                    {
                        if (C[k][mask ^ (1 << j)] + Cost[j][k] > C[j][mask])
                        {
                            C[j][mask] = C[k][mask ^ (1 << j)] + Cost[j][k];
                            Dad[j][mask] = k;
                        }
                    }
                }
            }
        }
    }

    /// Cautam nodul de start
    int sum = 0, nod = 0;
    for (int i = 0; i < n; i ++)
    {
        if (C[i][(1 << n) - 1] > sum)
        {
            sum = C[i][(1 << n) - 1];
            nod = i;
        }
    }

    /// Cautam lantul de cost maxim si lungine minima
    int mask = (1 << n) - 1, next_nod;
    while (nod > -1)
    {
        Sol.push_back(nod + 1);
        next_nod = Dad[nod][mask];
        mask -= (1 << nod);
        nod = next_nod;
    }

    /// Afisam solutia
    fout << S[Sol.front()];
    nod = Sol.front();
    for (int i = 1; i < Sol.size(); i ++)
    {
        int de_unde = Cost[nod - 1][Sol[i] - 1];
        //S[Sol[i]].erase(0, de_unde);
        fout << S[Sol[i]].substr(de_unde);
        nod = Sol[i];
    }

    fout.close();
    return 0;
}