Bzoj1195 [HNOI2006]最短母串 [状态压缩]
Submit: 1304 Solved: 439
Description
给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串。
Input
第一行是一个正整数n(n<=12),表示给定的字符串的个数。以下的n行,每行有一个全由大写字母组成的字符串。每个字符串的长度不超过50.
Output
只有一行,为找到的最短的字符串T。在保证最短的前提下,如果有多个字符串都满足要求,那么必须输出按字典序排列的第一个。
Sample Input
2
ABCD
BCDABC
ABCD
BCDABC
Sample Output
ABCDABC
HINT
Source
AC自动机+BFS:http://www.cnblogs.com/SilverNebula/p/6445516.html
状压DP+神(bao)奇(li)预处理
先找出所有被其他串包含的串并扔掉(显然)
暴力预处理出每两个串连接起来,公共部分的长度。
进行状压DP,暴力储存每个状态对应的字符串。
在所有的11111...的最终状态中,暴力找出字典序最小的那个
是不是很神(bao)奇(li)?
不知道为何,用strcmp会TLE(也可能是别的处理不到位),各处优化了一下,手写了比较函数,终于过了
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<queue> 6 using namespace std; 7 const int INF=0x3f3f3f3f; 8 const int mxn=61; 9 int n; 10 struct bind{ 11 char s[605]; 12 int len; 13 bool operator < (const bind y) const { 14 if(len!=y.len)return len<y.len; 15 for(int i=0;i<len;i++) 16 if(s[i]!=y.s[i])return s[i]<y.s[i]; 17 return 0; 18 } 19 }f[1<<12][12],s[12]; 20 int c[13][13]; 21 bool ban[mxn]; 22 23 bool ovl(int i,int j){//判断能否覆盖 24 if(s[i].len<s[j].len)return 0; 25 char *p=strstr(s[i].s,s[j].s); 26 if(p==NULL)return 0; 27 return 1; 28 } 29 int clc(int x,int y){//统计共用串长度 30 bool flag=0; 31 for(int i=max(0,s[x].len-s[y].len);i<s[x].len;i++){ 32 flag=1; 33 for(int j=i;j<s[x].len;j++) 34 if(s[x].s[j]!=s[y].s[j-i]){flag=0;break;} 35 if(flag)return s[x].len-i;//--1 36 } 37 return 0; 38 } 39 bind merge(int S,int u,int v){//字符串合并 40 bind tmp=f[S][u]; 41 strcat(tmp.s,s[v].s+c[u][v]); 42 tmp.len=f[S][u].len-c[u][v]+s[v].len; 43 // printf("merge:%d %d %d :%d\n",S,u,v,tmp.len); 44 return tmp; 45 } 46 void Dp(){ 47 int i,j,ed=(1<<n)-1; 48 for(i=0;i<=ed;i++) 49 for(j=0;j<n;j++)f[i][j].len=INF;//init 50 for(i=0;i<n;i++)f[1<<i][i]=s[i]; 51 for(i=1;i<=ed;i++){ 52 for(j=0;j<n;j++){ 53 if((i>>j)&1) 54 for(int k=0;k<n;k++){ 55 if((i>>k)&1)continue; 56 bind tmp=merge(i,j,k); 57 if(tmp<f[i|(1<<k)][k])f[i|(1<<k)][k]=tmp; 58 } 59 } 60 } 61 } 62 int main(){ 63 int i,j; 64 scanf("%d",&n); 65 for(i=0;i<n;i++)scanf("%s",s[i].s),s[i].len=strlen(s[i].s); 66 for(i=0;i<n;i++) 67 for(j=0;j<n;j++) 68 if(i!=j && ovl(i,j) && !ban[i])ban[j]=1; 69 int cnt=0; 70 for(i=0;i<n;i++)if(!ban[i])s[cnt++]=s[i]; 71 n=cnt; 72 for(i=0;i<n;i++) 73 for(j=0;j<n;j++) 74 if(i!=j)c[i][j]=clc(i,j); 75 Dp(); 76 int ans=0,ed=(1<<n)-1; 77 for(i=1;i<n;i++) 78 if(f[ed][i]<f[ed][ans])ans=i; 79 printf("%s",f[ed][ans].s); 80 return 0; 81 }
本文为博主原创文章,转载请注明出处。