状压的基础题吧
第一次看感觉难上天,后来嘛就。。
套路:先根据自身状态筛出可行状态,再根据地图等其他限制条件筛选适合的状态加入答案
f i,j,k 分别代表 行数,本行状态,上行状态,再累加答案即可
#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
using namespace std;
inline int read(){
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-;ch=getchar();}
while(isdigit(ch)){x=(x<<)+(x<<)+(ch^);ch=getchar();}
return x*f;}
inline int calc(int x){int ans=;for(;x;x-=x&(-x))ans++;return ans;}
//state 状态的具体集合
//num 状态的答案贡献(1数量)
int cnt,n,m;
int f[][][],num[],state[],g[];
void dp(){
int ans=;
memset(f,,sizeof f);
for(int i=;i<n;i++)//本行
for(int j=;j<cnt;j++){//本行状态
if(g[i]&state[j]) continue;
if(i==) f[i][j][]=num[j];
else if(i==){
for(int k=;k<cnt;k++){
if(g[i-]&state[k]) continue;
if(state[j]&state[k]) continue;
f[i][j][k]=max(f[i][j][k],f[i-][k][]+num[j]);
}
}else{
for(int k=;k<cnt;k++){
if(g[i-]&state[k]) continue;
if(state[j]&state[k]) continue;
for(int p=;p<cnt;p++){
if(g[i-]&state[p]) continue;
if(state[k]&state[p]||state[j]&state[p]) continue;
//三行都要兼容
f[i][j][k]=max(f[i][j][k],f[i-][k][p]+num[j]);
}
}
}
}
for(int j=;j<cnt;j++)
for(int k=;k<cnt;k++)
ans=max(ans,f[n-][j][k]);
printf("%d\n",ans);
}
int main(){
char s[];
int i,j;
n=read();m=read();
for(i=;i<n;i++){
scanf("%s",s);
for(j=;j<m;j++)
if(s[j]=='H') g[i]+=(<<(m--j));
}
int tmp;cnt=;
for(int i=;i<(<<m);i++){
tmp=i;
if(((tmp<<)&i)|((tmp<<)&i)) continue;
state[cnt]=i;
num[cnt]=calc(i);++cnt;}
//利用函数计算当前状态中1的数量
//cnt代表当前限制条件下合法状态
dp();return ;
}
//先根据自身条件确定状态
//再根据给定地图判断