给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串。
给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串。
第一行是一个正整数n(n<=12),表示给定的字符串的个数。以下的n行,每行有一个全由大写字母组成的字符串。每个字符串的长度不超过50.
只有一行,为找到的最短的字符串T。在保证最短的前提下,如果有多个字符串都满足要求,那么必须输出按字典序排列的第一个。
题解:状压dp
将答案中是否包含字符串i,状压起来。
f[i][j]表示到状态i,最前面的字符串为j 的最小连接方式的下一个串的编号
g[i][j] 表示状态i,最前面的字符串为j此时的长度
h[i][j]记录从哪个状态推来的。
转移的时候需要根据记录的后继还原出字符串进行对比
#include
#include
#include
#include
#include
#include
#define N 15
#define pa pair
using namespace std;
int f[(1<<12)][13],g[(1<<12)][13],h[(1<<12)][13],can[(1<<12)][13];
int n,m,ans,c[N][N];
char a[N][100],b[N][100],str[2000],s[603],s1[603];
int len[N],len1[N],mark[N];
int calc(char a[],char b[],int len,int len1)
{
int ans=0;
for (int i=1;i<=len;i++)
{
int j=1; int k=i;
while (a[k]==b[j]&&k<=len&&j<=len1) k++,j++;
if (k==len+1) ans=max(ans,j-1);
}
return ans;
}
bool pd(char x[],char y[],int len)
{
for (int i=1;i<=len;i++)
if (x[i]y[i]) return true;
return false;
}
int change(int x,int sta,int lenk,int last,char s[])
{
int t;
if (last==-1) t=calc(s,a[x],lenk,len[x]);
else t=c[last][x];
for (int i=t+1;i<=len[x];i++)
s[++lenk]=a[x][i];
if (f[sta][x]==0) return lenk;
change(f[sta][x],h[sta][x],lenk,x,s);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%s",b[i]+1);
len1[i]=strlen(b[i]+1);
}
for (int i=1;i<=n;i++)
if (!mark[i])
for (int j=1;j<=len1[i];j++)
{
for (int k=1;k<=n;k++)
if (k!=i)
{
bool f=true;
for (int l=1;l<=len1[k];l++)
if (b[i][j+l-1]!=b[k][l]){
f=false;
break;
}
if (f&&j+len1[k]-1<=len1[i])
mark[k]=1;
}
}
int cnt=0;
for (int i=1;i<=n;i++)
if (!mark[i]) {
cnt++; len[cnt]=len1[i];
for (int j=1;j<=len[cnt];j++)
a[cnt][j]=b[i][j];
}
n=cnt;
for (int i=1;i<=n;i++) c[0][i]=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (i!=j) c[i][j]=calc(a[i],a[j],len[i],len[j]);
memset(f,-1,sizeof(f));
queue p;
for (int i=1;i<=n;i++)
f[1<<(i-1)][i]=0,g[1<<(i-1)][i]=len[i],can[1<<(i-1)][i]=1,
p.push(make_pair(1<<(i-1),i));
while (!p.empty())
{
pa x=p.front(); p.pop();
int i=x.second; int sta=x.first; can[sta][i]=0;
for (int j=1;j<=n;j++)
if (!((sta>>(j-1))&1))
{
for (int k=1;k<=len[j];k++) s1[k]=a[j][k];
int t=change(i,sta,len[j],-1,s1);
if (f[sta|(1<<(j-1))][j]==-1)
{
f[sta|(1<<(j-1))][j]=i; h[sta|(1<<(j-1))][j]=sta;
g[sta|(1<<(j-1))][j]=t;
if (!can[sta|(1<<(j-1))][j]) p.push(make_pair(sta|(1<<(j-1)),j));
continue;
}
int l=change(j,sta|(1<<(j-1)),0,0,s);
if (t