bzoj 1195: [HNOI2006]最短母串 (状压dp)

来源:互联网 发布:python算法精解 pdf 编辑:程序博客网 时间:2024/05/21 17:05

1195: [HNOI2006]最短母串

Time Limit: 10 Sec  Memory Limit: 32 MB
Submit: 1212  Solved: 405
[Submit][Status][Discuss]

Description

给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串。

Input

第一行是一个正整数n(n<=12),表示给定的字符串的个数。以下的n行,每行有一个全由大写字母组成的字符串。每个字符串的长度不超过50.

Output

只有一行,为找到的最短的字符串T。在保证最短的前提下,如果有多个字符串都满足要求,那么必须输出按字典序排列的第一个。

Sample Input

2
ABCD
BCDABC

Sample Output

ABCDABC

HINT

Source

[Submit][Status][Discuss]


题解:状压dp

将答案中是否包含字符串i,状压起来。

f[i][j]表示到状态i,最前面的字符串为j 的最小连接方式的下一个串的编号

g[i][j] 表示状态i,最前面的字符串为j此时的长度

h[i][j]记录从哪个状态推来的。

转移的时候需要根据记录的后继还原出字符串进行对比

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<queue>#define N 15#define pa pair<int,int>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 false; else 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<pa> 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<l) { 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)); } else  if (t==l)  if (pd(s,s1,l))     {    f[sta|(1<<(j-1))][j]=i,h[sta|(1<<(j-1))][j]=sta;if (!can[sta|(1<<(j-1))][j]) p.push(make_pair(sta|(1<<(j-1)),j));  }   }   }int t=(1<<n)-1; ans=2000;for (int i=1;i<=n;i++) if (f[t][i]!=-1)  ans=min(ans,g[t][i]);for (int i=1;i<=600;i++) str[i]='Z';for (int i=1;i<=n;i++) if (g[t][i]==ans) {  int l=change(i,t,0,0,s);  if (pd(str,s,ans))    for (int j=1;j<=ans;j++) str[j]=s[j];     }for (int i=1;i<=ans;i++) printf("%c",str[i]);}



0 0
原创粉丝点击