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.BitSet;
import java.util.Comparator;
import java.util.Scanner;

public class Main{
	public static char[][] s;
	public static int[][] map;
	public static int n;
	public static void main(String[] args){
		Scanner in = new Scanner(System.in);
		Comp cmp = new Comp();
		while(true){
			n = in.nextInt();
			if(n == 0) break;
			s = new char[n][];
			for(int i=0; i<n; i++){
				s[i] = in.next().toCharArray();
			}
			Arrays.sort(s, cmp);
			map = new int[n][n];
			for(int i=0; i<n; i++){
				for(int j=0; j<n; j++){
					if(i==j) continue;
					map[i][j] = 0;
					for(int k=0; k<s[i].length; k++){
						boolean flag = true;
						int max = Math.min(s[i].length-k
								, s[j].length);
						for(int l=0; l<max; l++){
							if(s[i][l+k]!=s[j][l]){
								flag = false;
							}
						}
						if(flag){
							map[i][j] = s[i].length-k;
							break;
						}
					}
				}
			}
			max = n;
			res = Integer.MAX_VALUE;
			outPerm(max);
			System.out.println(resstr);
		}
	}
	
	public static String toStr(int[] arr){
		String str = "";
		for(int i=0; i<n; i++){
			if(i==0){
				str = String.valueOf(s[arr[i]]);
				continue;
			}
			int bk = arr[i-1];
			int nx = arr[i];
			if(map[bk][nx] < s[nx].length){
				str += String.valueOf(s[nx]).substring(map[bk][nx], s[nx].length);
			}
		}
		return str;
	}
	
	public static int max; // maxPn
	public static void outPerm(int n){
		int[] p = new int[n];
		BitSet used = new BitSet(n);
		for(int i=0; i<n; i++){
			used.set(i);
			p[0] = i;
			perm(p, i, 1, used, String.valueOf(s[i]).length());
			used.clear(i);
		}
	}
	
	public static int res;
//	public static int[] resarr;
	public static String resstr;
	public static void perm(int[] p, int back, int idx, BitSet used, int len){
		if(idx==max){
			if(res > len){
//				resarr = p.clone();
				res = len;
				resstr = toStr(p);
			}else if(res == len){
				String str = toStr(p);
				if(str.compareTo(resstr) < 0){
					resstr = str;
				}
			}
			return;
		}
		for(int i=used.nextClearBit(0); i!=-1 && i<max; i=used.nextClearBit(i+1)){
			used.set(i);
			p[idx] = i;
			perm(p, i, idx+1, used, len + (map[back][i] < s[i].length ? s[i].length-map[back][i] : 0));
			used.clear(i);
		}
	}
	
	public static void out(int[] p){
		for(int i=0; i<p.length; i++){
			System.out.print(p[i]);
		}
		System.out.println();
	}
}

class Comp implements Comparator<char[]>{
	@Override
	public int compare(char[] o1, char[] o2) {
		return String.valueOf(o1).compareTo(String.valueOf(o2)) ;
	}
}