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: Memory Limit Exceeded)

#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <algorithm>

using namespace std;

class State{
public:
  string str;
  int s, cnt;
  State() : str(""), s(0), cnt(cnt) {}
  State(string str, int s, int cnt) : str(str), s(s), cnt(cnt){}
  bool operator<(const State &p) const {
    return str.size() > (p.str).size();
    //if(cnt == p.cnt) return str.size() < (p.str).size();
    //return cnt < p.cnt;
  }
};

typedef pair<string, int> p;

int n;
vector<string> edge;
set<p> visited;



string bfs(){
  visited.clear();
  State u, v;
  priority_queue<State> Q;
  for(int i=0;i<n;i++){
    Q.push(State(edge[i], 1<<i, 1));
    visited.insert(p(edge[i], 1<<i));
  }
  while(!Q.empty()){
    u = Q.top();Q.pop();
    if(u.s == (1<<n)-1){
      return u.str;
    }
    for(int i=0;i<n;i++){
      if(u.s & (1<<i)) continue;
      if((u.str).size() >= edge[i].size()){
	bool f = false;
	for(int j=0;j+edge[i].size()<=(u.str).size();j++){
	  if((u.str).substr(j, edge[i].size()) == edge[i]){
	    if(visited.find(p(u.str, u.s|(1<<i))) == visited.end()){
	      Q.push(State(u.str, u.s|(1<<i), u.cnt+1));
	      visited.insert(p(u.str, u.s|(1<<i)));
	    }
	  }
	}
      }
      int size = min((u.str).size(), edge[i].size());
      for(int j=size;j>=0;j--){
	if((u.str).substr((u.str).size()-j) == edge[i].substr(0, j)){
	  if(visited.find(p(u.str+edge[i].substr(j), u.s|(1<<i))) == visited.end()){
	    Q.push(State(u.str+edge[i].substr(j), u.s|(1<<i), u.cnt+1));
	    visited.insert(p(u.str+edge[i].substr(j), u.s|(1<<i)));
	  }
	}
      }
    }
  }
}

main(){
  while(cin >> n && n){
    edge.clear();
    for(int i=0;i<n;i++){
      string in;
      cin >> in;
      edge.push_back(in);
    }
    /*for(int i=0;i<n;i++){
      for(int j=0;j<n;j++){
	if(edge[i].size() >= edge[j].size())
	  for(int k=0;k+(int)edge[j].size()<=edge[i].size();k++){
	    if(edge[i].substr(k, edge[j].size()) == edge[j]){
	      vector<string>::iterator ite = edge.begin();
	      for(int l=0;l<j;l++) ite++;
	      edge.erase(ite);
	      n--;
	    }
	  }
      }
      }*/
    sort(edge.begin(), edge.end());
    /*for(int i=0;i<n;i++){
      for(int j=0;j<n;i++){
	if(i == j) cost[i][j] == "";
	int size = min(edge[i].size(), edge[j].size());
	for(int k=size;k>=0;k--){
	  if(edge[i].substr(edge[i].size()-k) == edge[j].substr(0, k)){
	    cost[i][j] = edge[j].substr(k);
	  }
	}
      }
      }*/
    cout << bfs() << endl;
  }
  return 0;
}