给出不超过14个长度不超过20的字符串,要求出一个包含所有字符串的长字符串的最短的长度,根据题目数据范围可以知道要用状态DP,每个二进制位表示一个字符串,而且需要用二维的,dp[i][j]表示以j为开头的剩下的状态为i的最优值,转移方程也很好写。
View Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define N 15 5 #define inf 0x7fffffff 6 using namespace std; 7 int dp[1<<15][N]; 8 char str[N][25]; 9 int map[N][N]; 10 int min(int a,int b) 11 { 12 return a<b?a:b; 13 } 14 bool get(int i,int j) 15 { 16 if(strcmp(str[i],str[j])==0) 17 return true; 18 int len1=strlen(str[i]); 19 int len2=strlen(str[j]); 20 int l,k,p; 21 for(k=0;k<=len1-len2;k++) 22 { 23 for(p=0;p<len2&&k+p<len1;p++) 24 if(str[i][k+p]!=str[j][p]) 25 break; 26 if(p==len2) 27 return true; 28 } 29 for(k=0;k<=len2-len1;k++) 30 { 31 for(p=0;p<len1&&k+p<len2;p++) 32 if(str[i][p]!=str[j][k+p]) 33 break; 34 if(p==len1) 35 return true; 36 } 37 return false; 38 } 39 int getlen(int i,int j)//两个字符串连接增加的长度 40 { 41 int l,k,p; 42 int len1=strlen(str[i]); 43 int len2=strlen(str[j]); 44 int minlen=min(len1,len2); 45 for(l=minlen;l>=0;l--) 46 { 47 for(k=len1-l,p=0;k<len1&&p<len2;k++,p++) 48 if(str[i][k]!=str[j][p]) 49 break; 50 if(k==len1||p==len2) 51 return len2-l; 52 } 53 } 54 int n; 55 int dfs(int state,int k)//记忆化搜索的部分 56 { 57 if(dp[state][k]!=inf) 58 return dp[state][k]; 59 if(state==0) 60 return dp[0][k]=0; 61 int i,j,sta; 62 for(i=0;i<n;i++) 63 { 64 if(state&(1<<i)) 65 { 66 sta=state^(1<<i); 67 dp[state][k]=min(dp[state][k],dfs(sta,i)+map[k][i]); 68 } 69 } 70 return dp[state][k]; 71 } 72 int main() 73 { 74 int i,j; 75 int minn; 76 while(scanf("%d",&n)&&n) 77 { 78 for(i=0;i<n;i++) 79 { 80 scanf("%s",str[i]); 81 for(j=0;j<i;j++) 82 { 83 if(get(i,j)) 84 { 85 if(strlen(str[i])>strlen(str[j]))//有字符串被另一个包含的时候,把短的字符串直接覆盖掉 86 strcpy(str[j],str[i]); 87 i--; 88 n--; 89 } 90 } 91 } 92 for(i=0;i<n;i++) 93 for(j=0;j<n;j++) 94 { 95 map[i][j]=getlen(i,j); 96 } 97 for(i=0;i<(1<<n);i++) 98 for(j=0;j<n;j++) 99 dp[i][j]=inf; 100 int state=(1<<n)-1; 101 minn=inf; 102 for(i=0;i<n;i++) 103 { 104 minn=min(minn,dfs(state^(1<<i),i)+strlen(str[i])); 105 } 106 printf("%d\n",minn); 107 } 108 return 0; 109 }