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 }