HNU City Merger 【状态压缩DP】
题意: 求出包含样例所有子串的字符串的最小长度。
分析: dp[i][j] 表示在 i 状态下 ,以第 j 个字符串结尾的最优值。
#include<stdio.h> #include<string.h> #define INF 0x1f1f1f1f #define clr(x)memset(x,0,sizeof(x)) int min(int a,int b) { return a<b?a:b; } int dp[1<<16][16]; int g[16][16]; int add_s(char *s1,char *s2) // 求出 s2 串加在s1 串后增加的长度 { int i,j; int l1=strlen(s1); int l2=strlen(s2); for(i=0;i<l1;i++) { for(j=i;j<l1&&j-i<l2;j++) if(s1[j]!=s2[j-i]) break; if(j==l1) return l2-(l1-i); if(j-i==l2) return 0; } return l2; } int main() { int st,stat,i,j,k,n,tot,flag; char s[16][22]; while(scanf("%d",&n)!=EOF) { if(n==0) break; for(i=0;i<n;i++) scanf("%s",s[i]); tot=0; for(i=0;i<n;i++) // 去掉被包含的样例串 { flag=1; for(j=0;j<n;++j) if(i!=j&&strstr(s[j],s[i])) flag=0; if(flag) strcpy(s[tot++], s[i]); } n=tot; st=(1<<n)-1; for(i=0;i<n;i++) for(j=0;j<n;j++) g[i][j]=add_s(s[i],s[j]); memset(dp,INF,sizeof(dp)); for(i=0;i<n;i++) dp[1<<i][i]=strlen(s[i]); for(i=1;i<st;i++) for(j=0;j<n;j++) { if(dp[i][j]==INF) // 状态 i 中不包含 j 这个串 continue; for(k=0;k<n;k++) { if(i&(1<<k)) continue; // 状态 i 中包含了 第 k 个串 stat=i+(1<<k); dp[stat][k]=min(dp[stat][k],dp[i][j]+g[j][k]); } } int res=INF; for(i=0;i<n;i++) res=min(res,dp[st][i]); printf("%d\n",res); } return 0; }