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 <iostream>
#include <vector>
#include <cstring>
using namespace std;

int n;
int ansLen;
string ans;
vector<string> v;

int t[10][10];

void update(int *idx,int len){
  string s = v[idx[0]];

  for(int i=1;i<n;i++){
    for(int j=t[idx[i-1]][idx[i]];j<v[idx[i]].length();j++){
      s += v[idx[i]][j];
    }
  }

  if(ansLen > len || ansLen == len && ans > s){
    ansLen = len;
    ans = s;
  }
}

void dfs(int cnt,int *idx,bool *used,int len){
  if(cnt == n){
    if(ansLen >= len){
      update(idx,len);
    }
    return;
  }

  for(int i=0;i<n;i++){
    if(!used[i]){
      int nextLen = len + v[i].length();
      if(cnt != 0){
        nextLen -= t[idx[cnt-1]][i];
      }

      idx[cnt] = i;

      used[i] = true;
      dfs(cnt+1,idx,used,nextLen);
      used[i] = false;
    }
  }
}

int main(){
  while(cin>>n,n){
    v = vector<string>();

    for(int i=0;i<n;i++){
      string s;
      cin>>s;
      v.push_back(s);
    }

    for(int i=0;i<n;i++){
      for(int j=0;j<n;j++){
        if(i == j) continue;
        if(v[j].find(v[i]) != string::npos){
          v.erase(v.begin() + i);
          i--;
          n--;
          break;
        }
      }
    }

    memset(t,0,sizeof(t));

    for(int i=0;i<n;i++){
      for(int j=0;j<n;j++){
        if(i == j) continue;

        for(int k=min(v[i].length(),v[j].length())-1;k>0;k--){
          bool flg = true;
          for(int l=0;l<k;l++){
            if(v[j][l] != v[i][v[i].length()-k+l]){
              flg = false;
              break;
            }
          }
          if(flg){
            t[i][j] = k;
            break;
          }
        }
      }
    }

    ansLen = 999;
    ans = "zzzzzzzzzzzzzzzzzzzzz";

    int idx[n];
    bool used[n];
    memset(used,0,sizeof(used));

    dfs(0,idx,used,0);

    cout<<ans<<endl;
  }
}