#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char seqs[18][30008];
int kmppre[30008];
int kmpl=0;
int n;
/**
* dist[i][j] is the number of characters at the
* end of i that are found in the beginning of j
*/
int dist[18][18];
int sol[18];
int tsppre[262144][32];
int tspm[262144][32];
int tspord[262144];
void solve();
int main(int argc, char *argv[])
{
int i;
FILE *fin=fopen("adn.in","r");
fscanf(fin,"%d ",&n);
for (i=0; i<n; i++)
{
fscanf(fin,"%s ",seqs[i]);
//printf("%d %s\n",i,seqs[i]);
}
fclose(fin);
solve();
FILE *fou=fopen("adn.out","w");
fprintf(fou,"%s",seqs[sol[0]]);
//printf("%d",sol[0]);
for (i=1; i<n; i++)
{
//printf(" %d",sol[i]);
fprintf(fou,"%s",seqs[sol[i]]+dist[sol[i-1]][sol[i]]);
}
//fprintf(fou,"\n");
fclose(fou);
}
/**
* eliminate sequence i from the problem data and replace it by sequence
* [n-1]
*/
void dropseq(int i)
{
int j;
//printf("Eliminated %d %s\n",i,seqs[i]);
strcpy(seqs[i],seqs[n-1]);
for (j=0; j<n; j++) dist[i][j]=dist[n-1][j];
for (j=0; j<n; j++) dist[j][i]=dist[j][n-1];
n--;
}
/**
* for a corner case where one string is completely enclosed by another
*/
void dropseqs()
{
int i,j,d,l;
for (i=0; i<n; i++)
{
d=0;
for (j=0; j<n; j++) d|=dist[j][i]<0;
if (d) dropseq(i--);
}
}
/*
G A G A G A T A G A G A T A
0 0 1 2 3 4 0 0 1 2 3 4 0 0
A A A B A A A A B
0 1 2 0 1 2 3 3 4
*/
/**
* preprocessing for KMP, store result in kmppre
*/
void kmppreproc(const char *seq)
{
int i,t;
int l=strlen(seq);
kmpl=l;
kmppre[0]=0;
//for (i=0; i<l; i++) printf("%c ",seq[i]);
//printf("\n0 ");
for (i=1; i<l; i++)
{
t=kmppre[i-1]+1;
while (t>0)
{
if (seq[i]==seq[t-1]) break;
t=(t==1)?0:(kmppre[t-2]+1);
}
kmppre[i]=t;
//printf("%d ",t);
}
//printf("\n");
}
int kmpdist(const char *origseq, const int *kmppre, const char *seq)
{
int l=strlen(seq);
int i,r;
for (i=0; i<l; i++)
{
r+=1;
while (r>0)
{
if (seq[i]==origseq[r-1]) break;
r=(r==1)?0:(kmppre[r-2]+1);
}
if (r==kmpl) return -1;
}
return r;
}
void printdist()
{
int i,j;
for (i=0; i<n; i++)
{
for (j=0; j<n; j++)
printf("%2d ",dist[i][j]);
printf("(%d) %s\n",i,seqs[i]);
}
}
const char *nbin(int v)
{
static char a[32];
int i;
for (i=0; i<n; i++)
a[i]='0'+((v&(1<<i))!=0);
a[n]=0;
return a;
}
void tsp()
{
int i,q,w;
memset(tspm,0,sizeof(tspm));
memset(tsppre,0,sizeof(tspm));
q=0; // queue length
w=0; // queue out
for (i=0; i<n; i++)
{
tspm[1<<i][i]=1;
tsppre[1<<i][i]=0;
tspord[q++]=(1<<i)|(i<<18);
}
while (w<q)
{
int crtl=tspord[w++];
int crtx=crtl;
int crtb=crtl&0x3ffff;
crtl>>=18;
int crtm=tspm[crtb][crtl];
//printf("Expanding %s/%d benefit:%d\n",nbin(crtb),crtl,crtm);
for (i=0; i<n; i++)
{
if (crtb&(1<<i)) continue;
int nxtb=crtb|(1<<i);
int nxm=crtm+dist[crtl][i];
//printf(" -> %s/%d benefit:%d",nbin(nxtb),i,nxm);
if (tspm[nxtb][i]==0)
{
tspord[q++]=nxtb|(i<<18);
//printf(" new");
}
if (nxm>tspm[nxtb][i])
{
tspm[nxtb][i]=nxm;
tsppre[nxtb][i]=crtx;
//printf(" better");
}
//printf("\n");
}
}
int soll=0;
int solx=(1<<n)-1;
for (i=1; i<n; i++) if (tspm[solx][soll]<tspm[solx][i]) soll=i;
q=n;
while (solx!=0)
{
sol[--q]=soll;
int soly=tsppre[solx][soll];
//printf("Reconstruction benefit:%d pos:%d %s/%d\n",tspm[solx][soll],q,nbin(solx),soll);
soll=soly>>18;
solx=soly&0x3ffff;
}
}
void solve()
{
int i,j;
for (i=0; i<n; i++)
{
sol[i]=i;
kmppreproc(seqs[i]);
for (j=0; j<n; j++) if (i!=j)
{
dist[j][i]=kmpdist(seqs[i],kmppre,seqs[j]);
//printf("%s %d\n",seqs[j],dist[j][i]);
}
else dist[j][i]=0;
}
// printdist();
dropseqs();
// printdist();
tsp();
}