一开始以为这是字符串好题,一看n范围,n!就炸了。
考虑dp,dp[i][j] i表示每个子串有没有出现,j表示最后的串。
看了lych的博客之后,自己还是naive!首先有可能出现一个串没有用,要预处理掉,另外字典序最小需要存更多的东西。复杂度O(2^n*n*n*跑得过)。
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 13
using namespace std;
int n,m,l[N],fl[N],pre[N][N],dp[4096][N],b[N];
char s[N][51],c[4096][13][601];
bool same(int x,int a,int y,int b,int c)
{
for (int i=0;i<c;i++)
if (s[x][a+i]!=s[y][b+i]) return 0;
return 1;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%s",s[i]+1);
l[i]=strlen(s[i]+1);
}
//去重
for (int i=1;i<=n;i++)
for (int j=n+1;j<=n;j++)
if (l[i]>=l[j])
{
for (int k=1;k<=l[i]-l[j]+1;k++)
if (same(i,k,j,1,l[j]))fl[j]=1;
}
else
{
for (int k=1;k<=l[j]-l[i]+1;k++)
if (same(i,1,j,k,l[i]))fl[i]=1;
}
for (int i=1;i<=n;i++)
if (!fl[i])
{
l[++m]=l[i];
for (int j=1;j<=l[m];j++)
s[m][j]=s[i][j];
}
n=m;
//pre
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (i!=j)
{
int tmp=l[i]<l[j]?1:l[i]-l[j]+1;
for (;tmp<=l[i];tmp++)
if (same(i,tmp,j,1,l[i]-tmp+1)) break;
pre[i][j]=l[j]-l[i]+tmp-1;
}
//dp[i][j] i:状态 j:最后的串
b[1]=1;
for (int i=2;i<=n+1;i++)
b[i]=b[i-1]<<1;
memset(dp,0x3f,sizeof dp);
for (int i=1;i<=n;i++)
{
dp[b[i]][i]=l[i];
for (int j=1;j<=l[i];j++)
c[b[i]][i][j]=s[i][j];
}
for (int i=1;i<=b[n+1]-2;i++)
{
for (int j=1;j<=n;j++)
{
//cout<<dp[i][j]<<endl;
if (dp[i][j]>100000) continue;
for (int k=1;k<=n;k++)
if ((i&b[k])==0)
{
//cout<<i<<j<<k<<endl;
if (dp[i][j]+pre[j][k]<dp[i|b[k]][k])
{
dp[i|b[k]][k]=dp[i][j]+pre[j][k];
for (int p=1;p<=dp[i][j];p++)
c[i|b[k]][k][p]=c[i][j][p];
for (int p=1;p<=pre[j][k];p++)
c[i|b[k]][k][dp[i][j]+p]=s[k][l[k]-pre[j][k]+p];
}
else
{
if (dp[i][j]+pre[j][k]==dp[i|b[k]][k])
{
int fl=0;
for (int p=1;;p<=dp[i][j],p++)
{
if (c[i|b[k]][k][p]<c[i][j][p])
{fl=1;break;}
if (c[i|b[k]][k][p]>c[i][j][p])
{fl=2;break;}
}
if (fl==1) continue;
if (fl==2)
{
for (int p=1;p<=dp[i][j];p++)
c[i|b[k]][k][p]=c[i][j][p];
for (int p=1;p<=pre[j][k];p++)
c[i|b[k]][k][dp[i][j]+p]=s[k][l[k]-pre[j][k]+p];
continue;
}
for (int p=1;p<=pre[j][k];p++)
{
if (c[i|b[k]][k][pre[j][k]+p]<s[k][l[k]-pre[j][k]+p])
{fl=1;break;}
if (c[i|b[k]][k][pre[j][k]+p]>s[k][l[k]-pre[j][k]+p])
{fl=2;break;}
}
if (fl==1) continue;
if (fl==2)
{
for (int p=1;p<=pre[j][k];p++)
c[i|b[k]][k][dp[i][j]+p]=s[k][l[k]-pre[j][k]+p];
continue;
}
}
}
}
}
}
int Ans=1;
for (int i=2;i<=n;i++)
{
if (dp[b[n+1]-1][i]<dp[b[n+1]-1][Ans]) Ans=i;
else if (dp[b[n+1]-1][i]==dp[b[n+1]-1][Ans])
{
int fl=0;
for (int p=1;p<=dp[b[n+1]-1][i];p++)
{
if (c[b[n+1]-1][i][p]<c[b[n+1]-1][Ans][p])
{fl=2;break;}
if (c[b[n+1]-1][i][p]>c[b[n+1]-1][Ans][p])
{fl=1;break;}
}
if (fl==2)
Ans=i;
}
}
for (int i=1;i<=dp[b[n+1]-1][Ans];i++)
putchar(c[b[n+1]-1][Ans][i]);
//while(1);
}