Cod sursa(job #1587089)

Utilizator SilviuIIon Silviu SilviuI Data 1 februarie 2016 19:57:29
Problema ADN Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 7.25 kb
/*#include <fstream>
#include <string>
#include <vector>

using namespace std;

ifstream fin ("1.in");
ofstream fout ("1.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
        }
    }

    /// 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;
    }

    for (int i=0;i<Sol.size();i++) fout<<Sol[i]<<' ';
    fout<<endl;

    /// 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;
}


*/
#include <stdio.h>
#include <string>
#include <vector>
#include <iostream>
#define lmax 30010

using namespace std;

int n,st,nr;
int dp[20][lmax*10],path[20][lmax*10];
int urm[lmax],dif[20][20],sol[20];
bool del[20],viz[20][lmax*10];
string s[20];
char ss[lmax];
vector < pair<int,int> > g[20];

int memo(int nod,int mask)
{
    if (mask==0) return 0; else
    if (viz[nod][mask]) return dp[nod][mask];
    viz[nod][mask]=true;
    for (unsigned int i=0;i<g[nod].size();i++) {
        int y=g[nod][i].first;
        if (y==st && mask!=1<<y) continue;
        if (((mask>>(y-1))&1)==1) {
            int val=memo(y,mask-(1<<(y-1)))+g[nod][i].second;
            if (dp[nod][mask]<val) {
                dp[nod][mask]=val; path[nod][mask]=y;
            }
        }
    }
    return dp[nod][mask];
}

int nrbit(int x) { return (x&(x-1)); }

void findpath(int nod,int mask)
{
    if (nrbit(mask)==0) return; else
    {
        int x=path[nod][mask];
        nr++; sol[nr]=x;
        findpath(x,mask-(1<<(x-1)));
    }
}

int main()
{
    freopen("adn.in","r",stdin);
    freopen("adn.out","w",stdout);

    scanf("%d",&n);
    for (int i=1;i<=n;i++) {
        scanf("%s",ss); s[i]=ss; s[i].insert(0," ");
    }

    for (int i=1;i<=n;i++)
        if (!del[i]) {
            for (int j=1;j<=n;j++)
                if (i!=j && !del[j]) {
                    urm[1]=0; int k=0;
                    for (int l=2;l<(int)s[i].size();l++) {
                        while (k>0 && s[i][l]!=s[i][k+1]) k=urm[k];
                        if (s[i][l]==s[i][k+1]) k++;
                        urm[l]=k;
                    }

                    bool ok=false; k=0;
                    for (int l=1;l<(int)s[j].size();l++) {
                        while (k>0 && s[j][l]!=s[i][k+1]) k=urm[k];
                        if (s[j][l]==s[i][k+1]) k++;
                        if (k==s[i].size()-1) { ok=true; break; }
                    }

                    if (ok) { del[i]=true; break; }
                }
    }

    int m=0;
    for (int i=1;i<=n;i++)
        if (!del[i]) { m++; s[m]=s[i]; }

    n=m;

    for (int i=1;i<=n;i++) {
        for (int j=1;j<=n;j++)
        if (i!=j) {
            /*verific daca prefixul lui s[i] se regaseste ca sufix in s[j]; */
            urm[1]=0; int k=0;
            for (int l=2;l<(int)s[i].size();l++) {
                while (k>0 && s[i][l]!=s[i][k+1]) k=urm[k];
                if (s[i][l]==s[i][k+1]) k++;
                urm[l]=k;
            }

            k=0;
            for (int l=1;l<(int)s[j].size();l++) {
                while (k>0 && s[j][l]!=s[i][k+1]) k=urm[k];
                if (s[j][l]==s[i][k+1]) k++;
                if (k==s[i].size()-1) k=urm[k];
            }

            g[i].push_back(make_pair(j,k)); dif[i][j]=k;
        }
    }

    for (int i=1;i<=n;i++) s[i].erase(s[i].begin());

    int maxx=(1<<n)-1,best=0,ind=0;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=maxx;j++)
            dp[i][j]=-1;

    for (int i=1;i<=n;i++) {
        st=i;
        for (int j=0;j<g[i].size();j++) {
            int val=memo(g[i][j].first,maxx-(1<<(g[i][j].first-1)))+g[i][j].second;
            if (dp[i][maxx]<val) {
                dp[i][maxx]=val; path[i][maxx]=g[i][j].first;
            }
        }
    }

    for (int i=1;i<=n;i++)
        if (dp[i][maxx]>best) {
            ind=i; best=dp[i][maxx];
    }

    nr=1; sol[nr]=ind;
    findpath(ind,maxx);

    for (int i=1;i<nr;i++) {
        int y=dif[sol[i+1]][sol[i]];
        for (int j=0;j<s[sol[i]].size()-y;j++) printf("%c",s[sol[i]][j]);
    }
    //cout<<s[sol[1]];
    printf("\n");
    return 0;
}