这个题要求求最小长度的字符串,使得该字符串能够包含所给的所有的字符串。首先对于相互包含的字符串我们直接删除掉就行了,然后对于剩下的字符串我们依次去计算出拼接相同长度(前面的后缀和后面的前缀相同的长度)。然后进行状态压缩DP(过程比较麻烦),我的思路是用dp[i][j]表示在i状态下,最前面为j的时候的最小长度,至于为什么要用表示前面是为了后面更好的计算出最小的字典序(我尝试过后面,但是后面处理会非常麻烦)。求出最后DP值的时候只需要找到字典序最小的答案,然后用DFS向后搜索即可
代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
const int inf=1<<29;
const int maxn=110;
const int maxm=16;
struct String
{
char str[maxn];
int len;
bool operator < (const String &a)const
{
return strcmp(str,a.str)<0;
}
}str[maxm];
int n,ansl,dis[maxm][maxm],dp[1<<maxm][maxn];
string ans;
bool vis[maxm];
int Cal(int s1,int s2)
{
int lena=str[s1].len;
int lenb=str[s2].len;
for(int i=max((int)(lena-lenb),0);i<=lena;i++)
{
bool is=true;
for(int j=i,k=0;j<lena;k++,j++)
if(str[s1].str[j]!=str[s2].str[k])
{
is=false;
break;
}
if(is)
return lena-i;
}
return 0;
}
void Init()
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(i!=j)
dis[i][j]=Cal(i,j);
for(int i=0;i<(1<<n);i++)
for(int j=0;j<n;j++)
dp[i][j]=inf;
for(int i=0;i<n;i++)
dp[1<<i][i]=str[i].len;
}
void DFS(int cnt,int now,string s,int last)
{
if(cnt==n)
{
if(ans==""||ans>s)
ans=s;
return;
}
int id=-1;
string ss;
for(int i=0;i<n;i++)
{
if(!vis[i]&&dp[now][last]==dp[now^(1<<last)][i]+str[last].len-dis[last][i])
{
string s1=s;
for(int j=dis[last][i];j<str[i].len;j++)
s1+=str[i].str[j];
if(id==-1||ss>s1)
{
ss=s1;
id=i;
}
}
}
vis[id]=1;
DFS(cnt+1,now^(1<<last),ss,id);
}
int main()
{
int T,cas=1;
scanf("%d",&T);
while(T--)
{
ansl=inf;
scanf("%d",&n);
int cnt=0;
for(int i=0;i<n;i++)
{
scanf("%s",str[cnt].str);
str[cnt].len=strlen(str[cnt].str);
for(int j=0;j<cnt;j++)
{
if(strstr(str[j].str,str[cnt].str)!=NULL)
{
cnt--;
break;
}
if(strstr(str[cnt].str,str[j].str)!=NULL)
{
strcpy(str[j].str,str[cnt].str);
str[j].len=strlen(str[j].str);
cnt--;
break;
}
}
cnt++;
}
n=cnt;
sort(str,str+n);
Init();
for(int i=0;i<(1<<n);i++)
for(int j=0;j<n;j++)
if(dp[i][j]!=inf&&(i&(1<<j)))
for(int k=0;k<n;k++)
if(!(i&(1<<k)))
dp[i|(1<<k)][k]=min(dp[i|(1<<k)][k],dp[i][j]+str[k].len-dis[k][j]);
int pos=0;
for(int i=1;i<n;i++)
if(dp[(1<<n)-1][i]<dp[(1<<n)-1][pos])
pos=i;
memset(vis,0,sizeof(vis));
vis[pos]=1;
ans="";
DFS(1,(1<<n)-1,string(str[pos].str),pos);
printf("Scenario #%d:\n",cas++);
printf("%s\n",ans.c_str());
printf("\n");
}
return 0;
}