本题求用最短的长度字符串包含所给子串...由于存在多串匹配的问题...容易联想到AC自动机...


     最多14个city..用14位的二进制数表示已经在串中否...对多串构造Trie树..进一步构造好AC自动机...可以用dp [ k ] [ i  ] [ x ] 来表示长度为k的串..末字符落在trie树的i处..包含14个关系的x...但这样的复杂度..以最坏的考虑..会有240*240*16384=943718400=9*10^8...无法接受...

     那么此时就要压缩路径了..由于Trie树中有很多无法产生更新的点...没必要dp时一次又一次的路过...所以将Trie树中x非0的点找出来...从每个点开始BFS...做出到其他有效点的最短距离...这样大大优化了dp过程...     


Program:

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<stack>
#include<math.h>
#include<map>
#define oo 1000000000
using namespace std;
struct node
{
int fail,son[26],city,w;
}point[1001];
struct node2
{
int len,x;
};
int n,m,k,g,arc[303][303],need[303],l[303],dp[2][303][18000];
char s[30];
queue<int> myqueue;
void Built_Trie()
{
int len,i,j,k,h,x;
memset(point,0,sizeof(point));
m=0; g=1;
for (k=0;k<n;k++)
{
scanf("%s",s);
len=strlen(s);
h=0;
for (i=0;i<len;i++)
{
x=s[i]-'A';
if (!point[h].son[x]) point[h].son[x]=++m;
h=point[h].son[x];
}
point[h].w|=g;
g*=2;
}
g--;
return;
}
void Built_AC_Automation()
{
int i,h,k;
while (!myqueue.empty()) myqueue.pop();
for (i=0;i<26;i++)
if (point[0].son[i]) myqueue.push(point[0].son[i]);
while (!myqueue.empty())
{
h=myqueue.front();
myqueue.pop();
point[h].w|=point[point[h].fail].w;
for (i=0;i<26;i++)
{
k=point[h].fail;
while (!point[k].son[i] && k) k=point[k].fail;
point[point[h].son[i]].fail=point[k].son[i];
if (!point[h].son[i])
point[h].son[i]=point[k].son[i];
else
myqueue.push(point[h].son[i]);
}
}
return;
}
void Built_Arc()
{
int i,k,h,len[303];
memset(arc,-1,sizeof(arc));
n=0;
for (k=0;k<=m;k++)
if (point[k].w)
{
need[n++]=k;
point[k].city=n;
}
need[n]=0;
for (k=0;k<=n;k++)
{
h=need[k];
memset(len,-1,sizeof(len));
myqueue.push(h);
len[h]=0;
while (!myqueue.empty())
{
h=myqueue.front();
myqueue.pop();
i=h;
do
{
if (point[h].w && arc[k][point[h].city-1]==-1)
arc[k][point[h].city-1]=len[h];
i=point[i].fail;
}while (i);
for (i=0;i<26;i++)
if (len[point[h].son[i]]==-1)
{
len[point[h].son[i]]=len[h]+1;
myqueue.push(point[h].son[i]);
}
}
}
for (i=0;i<n;i++) l[i]=arc[n][i];
return ;
}
int EXE_DP()
{
int p,i,j,t,k,x,ans;
memset(dp,-1,sizeof(dp));
k=0;
for (i=0;i<n;i++) dp[k][i][point[need[i]].w]=l[i];
for (t=1;t<=n;t++)
{
k=1-k;
memset(dp[k],-1,sizeof(dp[k]));
for (i=0;i<n;i++)
for (j=0;j<n;j++)
for (p=0;p<=g;p++)
if (dp[1-k][j][p]!=-1)
{
x=point[need[i]].w|p;
if (dp[k][i][x]==-1 || dp[k][i][x]>dp[1-k][j][p]+arc[j][i])
dp[k][i][x]=dp[1-k][j][p]+arc[j][i];
}
}
ans=oo;
for (i=0;i<n;i++)
if (dp[k][i][g]!=-1 && dp[k][i][g]<ans) ans=dp[k][i][g];
return ans;
}
int main()
{
while (~scanf("%d",&n))
{
if (!n) break;
Built_Trie();
Built_AC_Automation();
Built_Arc();
printf("%d\n",EXE_DP());
}
return 0;
}