1 /*状态压缩就是把一系列用二进制表示的状态压缩成一个十进制数*/ 2 #include<stdio.h> 3 #include<string.h> 4 #include<iostream> 5 using namespace std; 6 int s[65],dp[150][65][65],cont=0,sum[65],map[150];//m为10根据要求每行最多60中状态 7 bool ok(int x) 8 { 9 if(x&(x<<1)) return false;//间隔1的不满足 10 if(x&(x<<2)) return false;//间隔2的不满足 11 return true; 12 } 13 int getsum(int x)//判断x有几个1,即这种状态能放多少大炮 14 { 15 int sum=0; 16 while(x>0) 17 { 18 if(x&1) sum++; 19 x>>=1; 20 } 21 return sum; 22 } 23 void init(int n)//初始化所有满足的状态 24 { 25 int i; 26 for(i=0;i<(1<<n);i++) 27 if(ok(i)) 28 { 29 s[cont]=i;//记录满足的状态,大炮占的位置为1,山地 位置为0; 30 sum[cont++]=getsum(i);//记录这种状态可以放多少门大炮 31 } 32 } 33 int max(int a,int b) 34 { 35 if(a>b) return a; 36 return b; 37 } 38 int main() 39 { 40 int i,j,n,m,k,r; 41 42 while(cin>>n>>m) 43 { 44 memset(dp,-1,sizeof(dp)); 45 for(i=0;i<n;i++) 46 { 47 for(j=0;j<m;j++) 48 { 49 char c; 50 cin>>c; 51 //printf("%c ",c); 52 //if(j==m-1) getchar(); 53 //a[i][j]=c; 54 if(c=='H') map[i]|=(1<<j);//记录实际的地形,有山的位置为1; 55 } 56 } 57 init(m); 58 for(i=0;i<cont;i++)//特别判断第一行; 59 if(!(s[i]&map[0])) //s[i]中大炮位置为1,map中山地位置为1,如果想与后的结果不为0说明大炮和山地位置相同,是不满足的,这行是筛选所有满足的状态中符合这个地形的 60 dp[0][0][i]=sum[i];//前面的0,0代表第0行的没有前面两行,所以第0行的 61 for(r=1;r<n;r++) 62 for(i=0;i<cont;i++)//枚举第r行 63 { 64 if(s[i]&map[r]) continue;//剪枝,如果状态j不满足地形 65 for(j=0;j<cont;j++)//枚举第r-1行 66 { 67 if(s[i]&s[j]) continue;//如果这两行的大炮在同一列 68 for(k=0;k<cont;k++)//枚举第r-2行 69 { 70 if(s[i]&s[k]) continue;// 71 if(dp[r-1][k][j]==-1) continue;//没这种状态存在 72 dp[r][j][i]=max(dp[r][j][i],dp[r-1][k][j]+sum[i]); 73 } 74 } 75 } 76 77 /*状态转移,从i到j,从k到j再从j到i,sum[i]是本行每种状态i的大炮个数, 78 j代表r-1行大炮的放法,i是本行的放法,因为这个关系是一层一层传下来的, 79 所以那么dp[r][j][i]代表的是从开始行到r行的最大炮个数,*/ 80 int ans = 0; 81 for(i = 0; i < cont; i ++) 82 for(j = 0; j <cont; j ++) 83 ans = max(ans,dp[n-1][i][j]); 84 printf("%d ",ans); 85 } 86 return 0; 87 } 88 89 90 /* 91 5 4 92 PHPP 93 PPHH 94 PPPP 95 PHPP 96 PHHP*/