这个题n<=15,可以用10表示选取情况下的最优值
预处理两个串之间的连接关系,然后枚举状态转移
然而这个题还要输出方案,,而且还不让你开空间。
所以只能记录前继动态判断、、
所以十分难写难调
码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,i,j,k,l,lin[15],g1[16385][15],g2[16385][15],er[15],daan2[15],p;
long long f[16385][15],lj[16][16],ans=2147483647,len[15];
char str[15][60],daan[800],lin3[800];
bool wu[15];
int main()
{
memset(f,0x7f,sizeof(f));
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%s",str[i]+1);
len[i]=strlen(str[i]+1);
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(i==j||len[i]>len[j])continue;
for(k=1;k<=len[j]-len[i];k++)
{
for(l=1;l<=len[i];l++)
{
if(str[i][l]!=str[j][k+l-1])break;
}
if(l>len[i])wu[i]=1;
}
}
int cnt=0;
for(i=1;i<=n;i++)
{
if(wu[i])continue;++cnt;
for(j=1;j<=len[i];j++)
str[cnt][j]=str[i][j];
len[cnt]=len[i];
}
n=cnt;
for(i=1;i<=n;i++)//最长延伸(第一个串)
{
for(j=1;j<=n;j++)
{
if(i==j)continue;
for(k=1;k<=len[i];k++)
{
for(l=1;l<=len[j];l++)
{
if(str[i][k+l-1]!=str[j][l])break;
}
if(k+l-2==len[i])
{
lj[i][j]=len[i]-k+1;
break;
}
}
}
}
er[0]=1;
for(i=1;i<=n;i++)
er[i]=er[i-1]*2;
for(i=1;i<=n;i++)
f[er[i-1]][i-1]=len[i],g1[er[i-1]][i-1]=-1;
for(i=1;i<er[n];i++)//枚举状态
{
for(j=0;j<n;j++)//枚举上一个是啥
{
for(k=0;k<n;k++)//枚举这一个放啥
{
if(i&er[k])continue;
if(f[i|er[k]][k]==f[i][j]+len[k+1]-lj[j+1][k+1]&&f[i|er[k]][k]<=1000000000)
{
//判断字典序;;;;;
//if(f[i|er[]])
int lin2=0;
int lol1=i,lol2=j;
while(lol1!=-1)//拆出前继 ,放到lin里,顺序是反的
{
lin[++lin2]=lol2+1;//位置要加1
int tmp=lol1;
lol1=g1[lol1][lol2];
lol2=g2[tmp][lol2];
}
int lin4=0;
lin[lin2+1]=0;
for(l=lin2;l>=1;l--)//倒着放字符
{
for(p=lj[lin[l+1]][lin[l]]+1;p<=len[lin[l]];p++)
{
lin3[++lin4]=str[lin[l]][p];
}
}
for(l=lj[j+1][k+1]+1;l<=len[k+1];l++)
{
lin3[++lin4]=str[k+1][l];
}
// for(int y=1;y<=lin4;y++)cout<<lin3[y];
// cout<<endl;
lin2=0;
lol1=i|er[k],lol2=k;
while(lol1!=-1)//拆出前继 ,放到daan2里,顺序是反的
{
daan2[++lin2]=lol2+1;
int tmp=lol1;
lol1=g1[lol1][lol2];
lol2=g2[tmp][lol2];
}
//看答案是否字典序
lin4=0;
daan2[lin2+1]=0;
for(l=lin2;l>=1;l--)
{
for(p=lj[daan2[l+1]][daan2[l]]+1;p<=len[daan2[l]];p++)
{
daan[++lin4]=str[daan2[l]][p];
}
}
// for(int y=1;y<=lin4;y++)cout<<daan[y];
// cout<<endl<<endl;
bool huan=0;
for(l=1;l<=f[i|er[k]][k];l++)
{
if(lin3[l]<daan[l]){huan=1;break;}
if(lin3[l]>daan[l]){break; }
}
if(huan)
{
g1[i|er[k]][k]=i;
g2[i|er[k]][k]=j;
}
}
if(f[i|er[k]][k]>f[i][j]+len[k+1]-lj[j+1][k+1])
{
f[i|er[k]][k]=f[i][j]+len[k+1]-lj[j+1][k+1];
g1[i|er[k]][k]=i;
g2[i|er[k]][k]=j;
}
}
}
}
for(i=0;i<n;i++)
ans=min(ans,f[er[n]-1][i]);
for(i=1;i<=ans;i++)daan[i]='a';
for(i=0;i<n;i++)
{
if(f[er[n]-1][i]==ans)
{
int lin2=n;
int lol1=er[n]-1,lol2=i;
while(lol1!=-1)
{
lin[lin2]=lol2+1;
int tmp=lol1;
lol1=g1[lol1][lol2];
lol2=g2[tmp][lol2];
lin2--;
}
//看答案是否字典序
int lin4=0;
for(j=1;j<=n;j++)
{
for(k=lj[lin[j-1]][lin[j]]+1;k<=len[lin[j]];k++)
{
lin3[++lin4]=str[lin[j]][k];
}
}
bool huan=0;
for(j=1;j<=ans;j++)
{
if(daan[j]>lin3[j])
{
huan=1;
break;
}
if(daan[j]<lin3[j])
break;
} if(huan)for(k=1;k<=ans;k++)
daan[k]=lin3[k];
}
}
for(i=1;i<=ans;i++)
printf("%c",daan[i]);
}