Cod sursa(job #1989846)

Utilizator georgerapeanuRapeanu George georgerapeanu Data 9 iunie 2017 08:44:20
Problema ADN Scor 60
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.48 kb
#include <cstdio>
#include <cstring>
#include <stack>
#include <bitset>
using namespace std;
FILE *f=fopen("adn.in","r");
FILE *g=fopen("adn.out","w");
int cst[20][20];
char rez[300005];
int ind;
int N;
char C[20][30005];
int dp[1<<18][19];
int ant[1<<18][19];
int L[20];
int F[30005];
bool inc;
int kmp(int a,int b)
{
    inc=0;
    F[1]=0;
    for(int i=2;i<=L[b];i++)
    {
        int k=F[i-1];
        while(k&&C[b][k+1]!=C[b][i])k=F[k];
        if(C[b][k+1]==C[b][i])k++;
        F[i]=k;
    }
    int j=0;
    for(int i=1;i<=L[a];i++)
    {
        while(j&&C[b][j+1]!=C[a][i])j=F[j];
        if(C[b][j+1]==C[a][i])j++;
        if(j==L[b])
        {
            j=F[j];
            inc=1;
        }
    }
    return j;
}
stack<int> S;
bitset<20>nok;
void solve()
{
    for(int i=1;i<=N;i++)
        for(int j=1;j<=N;j++)
            if(i!=j)
                cst[i][j]=kmp(i,j);
            else
                cst[i][j]=(1<<30);
    memset(dp,0x3f3f3f3f,sizeof(dp));
    dp[0][0]=0;
    for(int i=1;i<(1<<N);i++)
    {
        for(int j=1;j<=N;j++)
        {
            if(i&(1<<(j-1)))
            {
                for(int k=0;k<=N;k++)
                    if(((k!=j&&i&(1<<(k-1)))||k==0)&&dp[i][j]>dp[i^(1<<(j-1))][k]+(L[j]-cst[k][j]))
                    {
                        dp[i][j]=dp[i^(1<<(j-1))][k]+(L[j]-cst[k][j]);
                        ant[i][j]=k;
                    }
            }
        }
    }
    int imin=0;
    for(int i=1;i<=N;i++)
        if(dp[(1<<N)-1][i]<dp[(1<<N)-1][imin])imin=i;
    int conf=(1<<N)-1;
    while(conf)
    {
        S.push(imin);
        conf^=(1<<(imin-1));
        imin=ant[conf^(1<<(imin-1))][imin];
    }
    int pr=0;
    while(!S.empty())
    {
        for(int i=cst[pr][S.top()]+1;i<=L[S.top()];i++)
            rez[ind++]=C[S.top()][i];
        pr=S.top();
        S.pop();
    }
}
int main()
{
    fscanf(f,"%d\n",&N);
    for(int i=1;i<=N;i++){fgets(C[i]+1,30001,f);L[i]=strlen(C[i]+1);L[i]-=(C[i][L[i]]=='\n');}
    for(int i=1;i<=N;i++)
    {
        for(int j=1;j<=N;j++)
        {
            if(j==i)continue;
            kmp(j,i);
            if(inc&&!nok[j])nok[i]=1;
        }
    }
    int nN=0;
    for(int i=1;i<=N;i++)
    {
        if(!nok[i])
        {
            nN++;
            swap(C[nN],C[i]);
            swap(L[nN],L[i]);
        }
    }
    N=nN;
    solve();
    fputs(rez,g);
    fclose(f);
    fclose(g);
    return 0;
}