题目链接:http://poj.org/problem?id=1699
太爽了这题,1AC。容易想到用状态压缩DP来做,f[k][i][j]表示当前 i 状态有 k 个串并且串以 j 结尾的最短串。则 f[k][i][rt]=Min{ f[k][i][rt] , f[k][st][r]+len[j]+g[r][j] }。其中状态 i 用位运算表示所包含的具体的串,1010表示包含串2和4。这里要注意转移方程中的rt,要考虑串包含的情况。
1 //STATUS:C++_AC_0MS_324KB 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include<string.h> 5 #include<math.h> 6 #include<iostream> 7 #include<string> 8 #include<algorithm> 9 #include<vector> 10 #include<queue> 11 #include<stack> 12 #include<map> 13 using namespace std; 14 #define LL __int64 15 #define pii pair<int,int> 16 #define Max(a,b) ((a)>(b)?(a):(b)) 17 #define Min(a,b) ((a)<(b)?(a):(b)) 18 #define mem(a,b) memset(a,b,sizeof(a)) 19 #define lson l,mid,rt<<1 20 #define rson mid+1,r,rt<<1|1 21 const int N=11,INF=0x3f3f3f3f,MOD=10000,STA=8000010; 22 const double DNF=1e13; 23 24 char s[N][22]; 25 int f[2][1<<N][11],len[N],g[N][N],next[2][1<<N],cnt[2],vis[1<<N]; 26 int T,n; 27 28 void getg() 29 { 30 int i,j,k,p; 31 for(i=0;i<n;i++){ 32 for(j=0;j<n;j++){ 33 for(k=0;k<=len[i];k++){ 34 for(p=k;p<len[i] && p-k<len[j];p++) 35 if(s[i][p]!=s[j][p-k])break; 36 if(p==len[i] || p-k==len[j]){ 37 g[i][j]=Min(len[i]-k,len[j]); 38 break; 39 } 40 } 41 } 42 } 43 } 44 45 int main() 46 { 47 // freopen("in.txt","r",stdin); 48 int i,j,p,st1,k,r,st2,ans,rt; 49 scanf("%d",&T); 50 while(T--) 51 { 52 scanf("%d",&n); 53 for(i=0;i<n;i++){ 54 scanf("%s",s[i]); 55 len[i]=strlen(s[i]); 56 } 57 getg(); 58 59 mem(cnt,0); 60 mem(vis,0); 61 for(i=0;i<n;i++){ 62 next[0][cnt[0]]=1<<i; 63 f[0][1<<i][i]=len[i]; 64 cnt[0]++; 65 } 66 mem(f[p=1],INF); 67 for(i=1;i<n;i++){ 68 for(k=0;k<cnt[!p];k++){ 69 st1=next[!p][k]; 70 for(r=0;r<n;r++){ 71 if(st1&(1<<r)){ 72 for(j=0;j<n;j++){ 73 if(st1&(1<<j))continue; 74 st2=st1|(1<<j); 75 if(!vis[st2]){ 76 vis[st2]=1; 77 next[p][cnt[p]++]=st2; 78 } 79 if(g[r][j]==len[j])rt=r; 80 else rt=j; 81 f[p][st2][rt]=Min(f[p][st2][rt],f[!p][st1][r]+len[j]-g[r][j]); 82 } 83 } 84 } 85 } 86 mem(vis,0); 87 cnt[p=!p]=0; 88 mem(f[p],INF); 89 } 90 91 ans=INF; 92 k=(1<<n)-1; 93 for(i=0;i<n;i++) 94 ans=Min(ans,f[!p][k][i]); 95 printf("%d\n",ans); 96 } 97 return 0; 98 }