JZYZOJ1390【noi2001】炮兵阵地 状压DP

http://172.20.6.3/Problem_Show.asp?id=1390

需要储存该行和上一行两个状态。通过观察规则可以发现条件允许的状态很少(相邻两个至少空两格),据此可以减少状态数量,从而极大压缩空间和时间。
代码
 1 #include<iostream>  
 2 #include<cstdio>  
 3 #include<cstring>  
 4 #include<algorithm>  
 5 #include<cmath>
 6 using namespace std;
 7 const int maxn=110;
 8 int n,m,ma;
 9 char ch[12]={};
10 int ke[60]={},d[60]={},tot=0;
11 int a[maxn]={},f[maxn][60][60]={};
12 bool ca(int z){
13     if(z&(z<<1))return 0;
14     if(z&(z<<2))return 0;
15     return 1;
16 }
17 int main(){
18     memset(f,-1,sizeof(f));
19     scanf("%d%d",&n,&m);ma=1<<m;
20     for(int i=1;i<=n;i++){
21         scanf("%s",&ch);
22         for(int j=0;j<m;j++)
23             if(ch[j]=='H') a[i]|=(1<<(m-j-1));
24     }
25     for(int i=1;i<ma;i++){
26         if(ca(i)){
27             ke[++tot]=i;
28             for(int j=0;j<m;j++)
29                 if(i&(1<<j))d[tot]++;
30         }
31     }
32     for(int i=0;i<=tot;i++){
33         int w=a[1]&ke[i];
34         if(!w)
35             f[1][0][i]=d[i];
36     }int ans=0;
37     for(int i=2;i<=n;i++){
38         for(int w=0;w<=tot;w++){
39             for(int j=0;j<=tot;j++){
40                 if(ke[w]&ke[j])continue;
41                 if(ke[j]&a[i])continue;
42                 for(int j1=0;j1<=tot;j1++){
43                     if((ke[j1]&ke[j])||(ke[j1]&ke[w]))continue;
44                     f[i][w][j]=max(f[i-1][j1][w],f[i][w][j]);
45                 }
46                 f[i][w][j]+=d[j];
47                 ans=max(f[i][w][j],ans);
48             }
49         }
50     }printf("%d\n",ans);
51     return 0;
52 }
View Code

 

posted @ 2017-11-05 11:59  鲸头鹳  阅读(139)  评论(0编辑  收藏  举报