#include <iostream>
#include <fstream>
#include <cstring>
#include <vector>
#include <stack>
#include <string>
#define nmax 18
#define smax 30005
#define INF 0x3f3f3f3f
using namespace std;
ifstream f;
ofstream g;
vector<string> siruri;
vector<pair<int,int>> V[nmax];
vector<int> V2[nmax];
stack<int> stiva;
int n,s,dp[(1<<nmax)+1][nmax][2],mat_ad[nmax][nmax];
pair<pair<short,short>,bool> parent[(1<<nmax)+1][nmax];
void precompute(string a,int lps[])
{
int i=1,len=0;
int m=a.size();
lps[0]=0;
while(i<m)
{
if(a[i]==a[len]){
len++;
lps[i]=len;
i++;
}
else{
if(len!=0)
len=lps[len-1];
else{
lps[i]=0;
i++;
}
}
}
}
void kmp(string a,string b,int lps[],bool&ok)
{
int i=0,j=0;
int n=b.size(),m=a.size();
while(i<n&&!ok)
{
if(b[i]==a[j])
{
i++;
j++;
}
else if(i<n&&a[j]!=b[i])
{
if(j!=0)
j=lps[j-1];
else i++;
}
if(j==m)
{
ok=true;
}
}
}
void precompute_dinamica()
{
for(int i=0;i<(1<<n);i++)
for(int j=0;j<n;j++)
dp[i][j][0]=INF,dp[i][j][1]=INF;
}
void dinamica_exponentiala(int sursa)
{
precompute_dinamica();
dp[1<<sursa][sursa][0]=0;
dp[1<<sursa][sursa][1]=0;
for(int bitmask=(1<<sursa)+1;bitmask<(1<<n);bitmask++)///parcurgem submultimile
for(int i=0;i<n;i++)///parcurgem bitii din masca
if(i!=sursa&&bitmask&(1<<i))///tratam cazul de drum minim de la sursa la sursa(nehamiltonian)
{
for (auto j: V[i])
if (bitmask & (1 << j.first))///daca vecinul j pt care E j->i se afla in masca
{if(dp[bitmask ^ (1 << i)][j.first][0] + j.second<dp[bitmask][i][0])
{dp[bitmask][i][0] =dp[bitmask ^ (1 << i)][j.first][0] + j.second;
parent[bitmask][i]=make_pair(make_pair((short)bitmask^(1<<i),(short)j.first),(bool)0);}
}
for(auto j:V2[i])///arc special
if(bitmask&(1<<j))
{
int i2,j2,vmin=INF,checker=0;
if(dp[bitmask^(1<<i)][j][1]<dp[bitmask^(1<<i)][j][0])
vmin=dp[bitmask^(1<<i)][j][1];
else vmin=dp[bitmask^(1<<i)][j][0];
if(vmin<dp[bitmask][i][1])
dp[bitmask][i][1]=vmin,checker=1,parent[bitmask][i]=make_pair(make_pair((short)bitmask^(1<<i),(short)j),(bool)checker);
}
}
}
int main()
{
string s;
f.open("adn.in",ios::in);
g.open("adn.out",ios::out);
f>>n;
f.get();
for(int i=0;i<n;i++)
{
f>>s;
siruri.push_back(s);
}
string aux;
int lps[2*smax];
for(int i=0;i<n-1;i++)
{
for(int j=i+1;j<n;j++)
{
///calculam costul normal al arcului i->j
aux.append(siruri[j]);
aux.append("$");
aux.append(siruri[i]);
precompute(aux,lps);
int cost=siruri[j].size()-lps[aux.size()-1];
V[j].push_back(make_pair(i,cost));
mat_ad[i][j]=cost;
memset(lps,0,sizeof(lps));
aux.clear();
///calculam costul normal al arcului j->i
aux.append(siruri[i]);
aux.append("$");
aux.append(siruri[j]);
precompute(aux,lps);
int cost2=siruri[i].size()-lps[aux.size()-1];
V[i].push_back(make_pair(j,cost2));
mat_ad[j][i]=cost2;
memset(lps,0,sizeof(lps));
aux.clear();
///calculam costul special al arcului i->j(j se gaseste complet in i)
if(siruri[j].size()<=siruri[i].size())///cautam pe siruri[j] in siruri[i]
{
precompute(siruri[j],lps);
bool ok=false;
kmp(siruri[j],siruri[i],lps,ok);
if(ok==true)///se potriveste
V2[j].push_back(i);
memset(lps,0,sizeof(lps));
}
if(siruri[i].size()<=siruri[j].size())///cautam pe siruri[i] in siruri[j]
{
precompute(siruri[i],lps);
bool ok=false;
kmp(siruri[i],siruri[j],lps,ok);
if(ok==true)///se potriveste
V2[i].push_back(j);
memset(lps,0,sizeof(lps));
}
}
}
int dmin,smin,start;
dmin=INF,smin=-1,start=-1;
for(int k=0;k<n;k++) {
dinamica_exponentiala(k);
for (int i = 0; i < n; i++)
if (i != k) {
int dpmin=INF;
if(dp[(1 << n) - 1][i][0]<dpmin)
{
dpmin=dp[(1 << n) - 1][i][0];
}
if(dp[(1 << n) - 1][i][1]<dpmin)
{
dpmin=dp[(1 << n) - 1][i][1];
}
if (dpmin + siruri[k].size() < dmin) {
dmin = dpmin + siruri[k].size();
smin = k;
start = i;
}
}
}
dinamica_exponentiala(smin);
bool checker=0;
if(dp[(1<<n)-1][start][0]+siruri[smin].size()==dmin)
checker=0;
else checker=1;
int icurr=(1<<n)-1,jcurr=start,checkcurr=checker;
stiva.push(jcurr);
bool special[20];
while(icurr)
{
if(parent[icurr][jcurr].second)
special[parent[icurr][jcurr].first.second]=true;
int iaux=icurr,jaux=jcurr;
icurr=parent[iaux][jaux].first.first;
jcurr=parent[iaux][jaux].first.second;
stiva.push(jcurr);
}
stiva.pop();
string sol;
sol.append(siruri[stiva.top()]);
int nodcurr=stiva.top();
stiva.pop();
if(!special[nodcurr])
sol+=siruri[stiva.top()].substr(siruri[stiva.top()].size()-mat_ad[nodcurr][stiva.top()]);
while(stiva.size()>1)
{
nodcurr=stiva.top();
stiva.pop();
if(!special[nodcurr])
sol+=siruri[stiva.top()].substr(siruri[stiva.top()].size()-mat_ad[nodcurr][stiva.top()]);
}
g<<sol;
f.close();
g.close();
return 0;
}