POJ2817 WordStack(状压DP)

题目给几个字符串,可以给它们添加前导空格,然后排列,计算每一个字符串和前一个字符串相同非空格字符相等的个数,求可能的最大个数。

状态DP:

d[S][i][j]表示已经用的字符串集合S且排列的最后一个是前面带j个空格的字符串i

转移就枚举从什么字符串几个前导0结尾转移过来的。还可以预处理一下各个情况的字符串相同字符个数。时间复杂度大概就O(n2*100+2n*n2*100)。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 int d[1<<10][10][10],val[10][10][10][10];
 6 char str[11][11];
 7 int main(){
 8     int n;
 9     while(~scanf("%d",&n) && n){
10         memset(str,0,sizeof(str));
11         for(int i=0; i<n; ++i){
12             scanf("%s",str[i]);
13         }
14         memset(val,0,sizeof(val));
15         for(int i=0; i<n; ++i){
16             for(int j=0; j<n; ++j){
17                 if(i==j) continue;
18                 for(int x=0; x<10; ++x){
19                     for(int y=0; y<10; ++y){
20                         for(int k=max(x,y); str[i][k-x]&&str[j][k-y]; ++k){
21                             if(str[i][k-x]==str[j][k-y]) ++val[i][j][x][y];
22                         }
23                     }
24                 }
25             }
26         }
27         memset(d,0,sizeof(d));
28         for(int s=1; s<(1<<n); ++s){
29             for(int i=0; i<n; ++i){
30                 if(((s>>i)&1)==0) continue;
31                 for(int j=0; j<10; ++j){
32                     for(int x=0; x<n; ++x){
33                         if(x==i || ((s>>x)&1)==0) continue;
34                         for(int y=0; y<10; ++y){
35                             d[s][i][j]=max(d[s][i][j],d[s^(1<<i)][x][y]+val[i][x][j][y]);
36                         }
37                     }
38                 }
39             }
40         }
41         int res=0;
42         for(int i=0; i<n; ++i){
43             for(int j=0; j<10; ++j) res=max(res,d[(1<<n)-1][i][j]);
44         }
45         printf("%d\n",res);
46     }
47     return 0;
48 }

 

你可能感兴趣的:(POJ2817 WordStack(状压DP))