Problem:
Princess, a Cryptanalyst

お姫様の暗号解読

English text is not available in this practice contest.

ある貧乏な国のおてんばで勇敢なお姫様は，お忍びで出かけた町である日本語で書かれた古文書を手に入れた．お姫様は日本語ができるため，さっそくこの古文書を読んでみた．すると，驚くべき事が分かった．この古文書は，古の秘宝の在処を示していたのである．ところが，秘宝の在処は暗号になっており，容易には分からないようになっていた．そこでお姫様は，従者であるあなたに暗号の解読を手伝うように命令を下した．

あなたはお姫様を助けるため昼夜を問わず調査を行った．その結果，Shortest Secret String (SSS) と呼ばれる文字列が解読に重要な役割を果たすことがわかった．ここで SSS とは，N 個の単語全部を部分文字列として含み，なおかつその長さが最小であるような文字列である．

あなたの仕事は，N 個の単語から SSS を見つけ出す事である．

Input

入力は複数のデータセットで与えられる．データセットの初めの一行は，データセットに含まれる単語の数N(1≦N≦10)が与えられる．続くN行に単語が与えられる．最後のデータセットの後に，0のみを含む一行が与えられる．

なお，入力で与えられる単語はアルファベット小文字のみからなり，長さは高々10であることが保証されている．

Output

各データセットについてSSS を一行に出力せよ．また，複数ある場合は辞書式順序で最小のものを出力せよ．

Sample Input

4
apple
length
things
thin
2
icp
cpc
3
zeta
eta
alphabet
2
until
till
0

Output for the Sample Input

applengthings
icpc
zetalphabet
untill

Solution in C++ (judge verdict: Accepted)

#include <bits/stdc++.h>
using namespace std;
int n;
vector <string> str;
string mem[15][15];
typedef pair <string,int> P;

string con(string a,string b){
  int K=0;
  for(int i=0;i<a.size();i++){
    int j=i,k=0;
    while(a[j]&&b[k]&&a[j]==b[k]) j++,k++;
    if(!a[j]||!b[k])K=max(K,k);
  }
  return b.substr(K,b.size());
}

string solve(){
  string dp[1<<14][14];
  for(int i=0;i<n;i++) dp[1<<i][i]=str[i];
  
  for(int i=0;i<(1<<n);i++)
    for(int k=0;k<n;k++){
      if(dp[i][k]=="")continue;
      for(int j=0;j<n;j++){
	if((i&(1<<j)))continue;
	string nx=dp[i][k]+mem[k][j];
	int ni=i|1<<j;
	if(!dp[ni][j].size()||
	   nx.size()<dp[ni][j].size()||
	   (nx.size()==dp[ni][j].size()&&dp[ni][j]>nx))dp[ni][j]=nx;
      }
    }

  string res=dp[(1<<n)-1][0];
  for(int i=1;i<n;i++) {
    string a=dp[(1<<n)-1][i];
    if(res.size()>a.size()||(a.size()==res.size()&&res>a)) res=a;
  }
  return res;
}

int main(){
  
  while(cin>>n,n){
    str.resize(n);
    for(int i=0;i<n;i++)cin>>str[i];

    for(int i=0;i<n;i++)
      for(int j=0;j<n;j++)
	if(i!=j&&con(str[i],str[j])==""){
	  str.erase(str.begin()+j);
	  n--;
	  i=-1;
	  break;
	}
    
    for(int i=0;i<n;i++)
      for(int j=0;j<n;j++)mem[i][j]=con(str[i],str[j]);

    cout<<solve()<<endl;
  }

  return 0;
}