KMP+状态DP
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
char q[1200000],p[1200000];
int nex[1200000];
void getnext()
{
int len=strlen(q),i,j,k=0,l;
nex[0]=-1;i=0;j=-1;
while(i<len){
if(j==-1 || q[i]==q[j]){
++i;++j;nex[i]=j;
}
else
j=nex[j];
}
}
int kmp()
{
int i=0,n=strlen(p),m=strlen(q),l=-1;
getnext();
while(i<n && l<m){
if(l==-1 || p[i]==q[l]){
++i;
++l;
}
else
l=nex[l];
}
if(l>=m)
return 1;
return 0;
}
char ss[16][300100],s[16][300100];
char str[310000];
int dp[1<<16][16];
int a[16][16];
int main()
{
int i,j,k,n;
while (scanf("%d",&n)!=EOF)
{
int sum=0;
for (i=0;i<n;i++)
scanf("%s",ss[i]);
int pp=0;
for (i=0;i<n;i++)
{
for (j=i+1;j<n;j++)
{
strcpy(q,ss[i]);
strcpy(p,ss[j]);
if (kmp())break;
}
if (j==n)strcpy(s[pp++],ss[i]);
}
n=pp;
for (i=0;i<n;i++)
sum+=strlen(s[i]);
for (i=0;i<n;i++)
{
for (j=0;j<n;j++)
{
if (i==j)a[i][j]=0;
else
{
strcpy(q,s[j]);
strcat(q,s[i]);
int l=strlen(q);
getnext();
a[i][j]=nex[l];
}
}
}
memset(dp,0,sizeof(dp));
for (i=1;i<(1<<n)-1;i++) //从i推向下面的状态
{
for (j=0;j<n;j++)
{
if (i&(1<<j))
{
for (k=0;k<n;k++)
{
if ((i&(1<<k)))continue;
dp[i|(1<<k)][k]=max(dp[i|(1<<k)][k],dp[i][j]+a[j][k]);
}
}
}
}
int ans=0;
for (i=0;i<n;i++)
ans=max(ans,dp[(1<<n)-1][i]);
printf("%d\n",sum-ans);
}
return 0;
}