HDU2167 Pebbles(状压DP)

题目给一张n×n的格子,每个格子都有数字,要从格子中取若干个数字,八个方向相邻的数字不能一起取,问取的数字最大和是多少。

从第一行一行一行看下去,可以发现第1行取哪几列只会影响到第2行,第3行后面的一点影响都没有。即第i行的决策只受i-1行决策的影响。

那么自然想到状态DP——

  • dp[i][S]前i行其中第i行取的列的集合是S的取数最大和
  • dp[i][S]=max(dp[i-1][S'])+集合S数字和(S是S'的合法的下一行的取法)

虽然题目n最多15,集合S就215种状态,但事实上合法的(不能同时取同一行相邻的两列数字)集合S状态只有1000多个。枚举即可转移,为了保证时间复杂度做一些预处理就行了。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 #include<algorithm>
 5 using namespace std;
 6 int read(char *&s){
 7     int res=-1;
 8     sscanf(s,"%d",&res);
 9     while(*s==' ') ++s;
10     while(*s>='0' && *s<='9') ++s;
11     while(*s==' ') ++s;
12     return res;
13 }
14 int n,a[15][15],d[15][1<<15],sta[1<<15],sn;
15 bool isok(int s){
16     for(int i=1; i<n; ++i){
17         if(((s>>i-1)&1) && ((s>>i)&1)) return 0;
18     }
19     return 1;
20 }
21 bool isok(int x,int y){
22     for(int i=0; i<n; ++i){
23         if(((x>>i)&1)==0) continue;
24         if((y>>i)&1) return 0;
25         if(i>0 && ((y>>i-1)&1)) return 0;
26         if(i<n-1 && ((y>>i+1)&1)) return 0;
27     }
28     return 1;
29 }
30 int main(){
31     char str[1111];
32     while(gets(str) && *str){
33         n=0;
34         char *s=str; int t;
35         while(t=read(s),t!=-1) a[0][n++]=t;
36         for(int i=1; i<n; ++i){
37             gets(str); s=str;
38             for(int j=0; j<n; ++j) a[i][j]=read(s);
39         }
40         sn=0;
41         for(int i=0; i<(1<<n); ++i){
42             if(isok(i)) sta[sn++]=i; 
43         }
44         memset(d,0,sizeof(d));
45         for(int i=0; i<sn; ++i){
46             for(int j=0; j<n; ++j){
47                 if((sta[i]>>j)&1) d[0][sta[i]]+=a[0][j];
48             }
49         }
50         vector<int> vec[2222];
51         for(int i=0; i<sn; ++i){
52             for(int j=0; j<sn; ++j){
53                 if(isok(sta[i],sta[j])) vec[i].push_back(j);
54             }
55         }
56         for(int i=1; i<n; ++i){
57             for(int j=0; j<sn; ++j){
58                 for(int k=0; k!=vec[j].size(); ++k) d[i][sta[j]]=max(d[i][sta[j]],d[i-1][sta[vec[j][k]]]);
59                 for(int k=0; k<n; ++k){
60                     if((sta[j]>>k)&1) d[i][sta[j]]+=a[i][k];
61                 }
62             }
63         }
64         int res=0;
65         for(int i=0; i<sn; ++i){
66             res=max(res,d[n-1][sta[i]]);
67         }
68         printf("%d
",res);
69         getchar();
70     }
71     return 0;
72 } 
原文地址:https://www.cnblogs.com/WABoss/p/5188403.html