又是一道状压dp经典题!
#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#define M 1<<10
#define N 105
using namespace std;
int dp[N][N][N],mp[N],a[N],b[N],n,m,ToT;
bool judge(int x) {
bool ret=true;
if (x&(x<<1)) ret=false;//相差距离为1
if (x&(x<<2)) ret=false;//相差距离为2
return ret;
}
int count(int x) {//数有多少个炮兵
int ret=0;
for (;x;x>>=1)
if (x&1) ret++;
return ret;
}
void init() {
for (int i=0;i<(1<<m);i++)
if (judge(i)) a[++ToT]=i,b[ToT]=count(i);
}
bool check(int x,int y) {return (mp[x]&a[y])==0?true:false;}//是否放在了山上
bool check2(int x,int y){return (a[x]&a[y])==0?true:false;}//是否相互打到
int solve() {
int ret=0;memset(dp,-1,sizeof(dp));
dp[0][0][0]=1;
for (int i=1;i<=ToT;i++) {//首先预处理出第一行
if (check(1,i)) {
dp[1][i][1]=b[i];
ret=max(ret,dp[1][i][1]);
}
}
for (int i=2;i<=n;i++) {
for (int j=1;j<=ToT;j++) {
if (check(i,j)) {
for (int k=1;k<=ToT;k++) {
if (check(i-1,k)&&check2(j,k)) {//前一行
int cur=0;
for (int l=1;l<=ToT;l++)//再前一行
if (check(i-2,l)&&check2(j,l))
cur=max(dp[i-1][k][l],cur);
dp[i][j][k]=max(dp[i][j][k],cur+b[j]);
if (i==n) ret=max(dp[i][j][k],ret);
}
}
}
}
}
return ret;
}
int main() {
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) {
char ch=getchar();
for (;!isalpha(ch);ch=getchar());//防止读入空格
if (ch=='H') mp[i]|=1<<(m-j);//如果不能放的话就标记
}
init();
printf("%d\n",solve());
return 0;
}