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 JAVA (judge verdict: Wrong Answer)

import java.util.Arrays;
import java.util.Scanner;

//Princess, a Cryptanalyst
public class Main{

	int n;
	int[][] cut;
	String[][] dp;
	String[] s;
	String INF = "?";
	
	String get(int S, int last){
		if(!INF.equals(dp[S][last]))return dp[S][last];
		int ns = S-(1<<last);
		if(ns==0)return dp[S][last] = s[last];
		String res = INF;
		for(int k=0;k<n;k++){
			if(((ns>>k)&1)==0)continue;
			String r = get(ns, k)+s[last].substring(cut[k][last]);
			if(comp(r, res)<0)res = r;
		}
		return dp[S][last] = res;
	}
	
	int comp(String a, String b){
		if(INF.equals(a))return 1;
		if(INF.equals(b))return -1;
		if(a.length()!=b.length())return a.length()-b.length();
		return a.compareTo(b);
	}
	
	void run(){
		Scanner sc = new Scanner(System.in);
		for(;;){
			int N = sc.nextInt();
			if(N==0)break;
			String[] t = new String[N];
			for(int i=0;i<N;i++)t[i]=sc.next();
			boolean[] del = new boolean[N];
			for(int i=0;i<N;i++)for(int j=0;j<N;j++){
				if(i==j)continue;
				if(t[i].contains(t[j]))del[j] = true;
			}
			n = 0;
			for(boolean f:del)if(!f)n++;
			s = new String[n];
			int id = 0;
			for(int i=0;i<N;i++)if(!del[i])s[id++] = t[i];
			cut = new int[n][n];
			for(int i=0;i<n;i++)for(int j=0;j<n;j++){
				if(i==j)continue;
				for(int k=0;k<s[i].length();k++){
					if(s[j].startsWith(s[i].substring(k))){
						cut[i][j] = s[i].length()-k; break;
					}
				}
			}
			dp = new String[1<<n][n];
			for(String[]a:dp)Arrays.fill(a, INF);
			String res = INF;
			for(int i=0;i<n;i++){
				String r = get((1<<n)-1, i);
				if(comp(r, res)<0)res = r;
			}
			System.out.println(res);
		}
	}
	
	public static void main(String[] args) {
		new Main().run();
	}
}