poj 2817 WordStack 【状态压缩DP】
题意: 有 n 个字符串,可以改变上下顺序,可以在每个单词前加 任意的空格,计算所有单词叠在一起后每一行与上一行相应位置相同的字符数之和,找出最大和。
分析: 两两字符串之间可以用 l *l 的算法计算出最大的连续相同的字符数,由于单词前可以加任意的空格数,所以单词的上下顺序不影响结果,由于字符串的长度最大为10 ,总的个数最多为10,所以可以枚举所有状态,找出最大值。
#include<stdio.h> #include<string.h> #define clr(x)memset(x,0,sizeof(x)) int max(int a,int b) { return a>b?a:b; } int dp[1<<12][12]; int g[12][12]; int c_s(char *s1,char *s2) // 最长公共连续子串 { int tot=0; int tmp,i,j; int len1=strlen(s1); int len2=strlen(s2); for(i=0;i<11;i++) { tmp=0; for(j=0;j<len1&&i+j<len2;j++) tmp+=(s1[j]==s2[i+j]); tot=max(tot,tmp); } return tot; } int main() { //freopen("D:ce.txt","r",stdin); int st,stat,i,j,k,x,y,n; char s[12][12]; while(scanf("%d",&n),n) { st=(1<<n)-1; for(i=0;i<n;i++) scanf("%s",s[i]); for(i=0;i<n;i++) for(j=0;j<i;j++) g[i][j]=g[j][i]=max(c_s(s[i],s[j]),c_s(s[j],s[i])); memset(dp,0xff,sizeof(dp)); for(i=0;i<n;i++) dp[1<<i][i]=0; int stat; for(i=1;i<st;i++) for(j=0;j<n;j++) { if(dp[i][j]<0) // 状态 i 中不包含 j 这个串 continue; for(k=0;k<n;k++) { if(i&(1<<k)) continue; // 状态 i 中包含了 第 k 个串 stat=i+(1<<k); dp[stat][k]=max(dp[stat][k],dp[i][j]+g[j][k]); } } int res=0; for(i=0;i<n;i++) res=max(res,dp[st][i]); printf("%d\n",res); } return 0; }