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

/*
  AOJ 2022
 */
#include <stdio.h>
#include <string.h>

int N;
int num[11];
int frag[11];
int ordr[11];
int prev_ordr[11];
char words[11][11];
char result[101];
char result_partial[11][101];
int  result_partial_len[11];
char shortest[101];

void reverse(int* from ,int *to)
{
  int i;

  for(i=1;i<=N;i++)
    to[i]=from[N+1-i];
}

extern void strcat_erase_common(char *,char *);
int update_shortest(char * r)
{
  if(shortest[0]=='\0' || (strlen(shortest)>strlen(r))
     || ((strlen(shortest)==strlen(r)) && 0<strcmp(shortest,r)))
    {
      strcpy(shortest,r);
    }
}
int strcat_order(int * order)
{
  int i,from;
#ifdef DEBUG
  for(i=1;i<=N;i++)
    printf("%d:",order[i]);
  printf("\n");
#endif
  for(i=1;i<=N;i++)
    if(order[i] != prev_ordr[i]) 
      break;

    from=i-1;
#ifdef DEBUG
    printf("from:%d\n",from);
#endif


  if(from==0)
    {
      memset(&result[0],'\0',11);
    }
  else
    {
      //memset(&result[0],'\0',101);
      //strcpy(&result[0],&result_partial[from][0]);
      result[result_partial_len[from]]='\0';
      //printf("p:%s\n",&result[0]);
    }
  //printf("p:%s\n",&result[0]);
  for(i=from+1;i<=N;i++)
    {
      strcat_erase_common(result,&words[order[i]][0]);
      //printf("%s:",&words[order[i]][0]);
      if(i<N-1)
	{
	  strcpy(&result_partial[i][0],result);
	  result_partial_len[i]=strlen(result);
	}
    }
 SKIP:
  memcpy(prev_ordr,order,11*sizeof(int));
  return(-1);
}

void strcat_erase_common(char * buf,char *add)
{
  int i,len;

  if(strstr(buf,add))
    return;

  len=strlen(buf);
  for(i=strlen(add)-1;i>0;i--)
    if(0==strncmp(buf+len-i,add,i))
      {
      strcat(buf,add+i);
      return;
      }
  strcat(buf,add);
  return;
}

void fx(int n,int k)
{
  int i,f,j,ret;

  if(n==1)
    {
      strcpy(shortest,&words[1][0]);
      return;
    }

  for(i=0;i<n;++i)
    {
      f=frag[i];
      if(f == 0)
	{
	  frag[i]=1;
	  num[k] = i+1;
	  if(k==1)
	    {
	      reverse(num,ordr);
	      ret=strcat_order(ordr);
#ifdef DEBUG2
	      printf("%s\n",result);
#endif
	      if(ret)
		update_shortest(result);
	    }
	  else
	    {
	      fx(n,k-1);
	    }
	  frag[i] = 0;
	}
    }
}

int main()
{
  int i,k;


 while(EOF!=scanf("%d",&N) && N)
   {
     memset(num,0,N*sizeof(int));
     memset(frag,0,N*sizeof(int));

     for(i=1;i<=N;i++)
       scanf("%s ",&(words[i][0]));
#ifdef DEBUG2
  for(i=1;i<=N;i++)
    printf("%s:",&words[i][0]);
  printf("\n");
#endif
     memset(shortest,'\0',100);
     memset((char *)result_partial,'\0',10*101);
     memset(prev_ordr,0,sizeof(int)*10);
     
     fx(N,N);
     printf("%s\n",shortest);
   }
 return(0);
}