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.*;
import java.util.regex.Pattern;

public class Main {

	final int INF = 1 << 24;
	private void doit(){
		Scanner sc = new Scanner(System.in);
		//System.out.println(Pattern.matches(".*ikeya.*","aikeyaa"));
		while(true){
			int n = sc.nextInt();
			if(n == 0) break;
			String [] data = new String[n];
			int index = 0;
			for(int i=0; i < n; i++){
				data[index] = sc.next();
				boolean flg = false;
				for(int j = index-1 ; j >= 0; j--){
					if(Pattern.matches(".*"+data[index]+".*",data[j])){
						//System.out.println("pass = " + i + " " + j);
						flg = true;
						break;
					}
				}
				if(! flg) index++;
				//System.out.println("index= " + index);
			}
			n = index;
			
//			for(int i = 0; i < n; i ++){
//				System.out.println("data= " + data[i]);
//			}
			int len = 1 << n;
			int [][] dp = new int[n][len];
			String [][] dpStr = new String[n][len];
			for(int i =0; i < n; i++){
				Arrays.fill(dp[i], INF);
				Arrays.fill(dpStr[i], "");
			}
			for(int i = 0; i < n; i++){
				dp[i][1 << i] = data[i].length();
				dpStr[i][1 << i] = data[i];
			}

			for(int i = 0; i <len; i++ ){
				for(int j = 0; j < n;j++){
					if(dp[j][i] == INF) continue;
					for(int k = 0; k < n; k++){
						if((i & (1 << k)) != 0) continue;
						int ind = i | (1 << k);
						int addlen = getlen(data[j],data[k]);
						int klen = data[k].length();
						int value = addlen + dp[j][i];
						//System.out.println("ind= " + ind + "value= "+ (value) + "dp=" + dp[j][i]);
						//dp[k][ind] = Math.min(dp[k][ind], dp[j][i] + value);
						if(dp[k][ind] > value){
							dp[k][ind] = value;
							
							String addStr = data[k].substring(klen - addlen, klen);
							//System.out.println("as = " + addStr);
							dpStr[k][ind] = dpStr[j][i] + addStr;
						}
						else if(dp[k][ind] != INF && dp[k][ind] == value){
							String addStr = data[k].substring(klen - addlen, klen);
							String nextStr = dpStr[j][i] + addStr;
							if(dpStr[k][ind].compareTo(nextStr) > 0){
								dpStr[k][ind] = nextStr;
							}
							
						}
					}
				}
			}
//			
//			for(int i=0; i < n; i++){
//				for(int j = 0; j < len; j++){
//					System.out.print(dpStr[i][j]+ i+ j + " ");
//				}
//				System.out.println();
//			}
			int ans = INF;
			String str = "";
			for(int i=0; i < n; i++){
				//ans = Math.min(ans, dp[i][len-1]);
				if(ans > dp[i][len-1]){
					ans = dp[i][len-1];
					str = dpStr[i][len-1];
				}
				else if(ans != INF && ans == dp[i][len-1]){
					if(str.compareTo(dpStr[i][len-1]) > 0){
						str = dpStr[i][len-1];
					}
				}
			}
			//System.out.print("ANS= ");
			//System.out.print(" " + ans +" ");
			System.out.println(str);
			
		}
	}
	private int getlen(String a, String b) {
		int res=b.length(),i = 0;
		//System.out.println(b + " " + b.length());
		StringBuilder sb = new StringBuilder();
		for(i=0; i < b.length() && i < a.length();i++){
			sb.append("" + b.charAt(i));
			if(a.endsWith(sb.toString())){
				
				res = b.length() - i- 1;
				//System.out.println(res + " " + sb.toString() + " " + i );
			}
		}
		//System.out.println(res);
		return res;
	}
	public static void main(String[] args) {
		Main obj = new Main();
		obj.doit();
	}
}