菜鸡的我这道题想了半天。
具体解释看代码喽:
/*
!((x&(x>>1))||(x&(x>>2)))
这是看这个状态的每个1,向前两位是不是1,向前1位是不是1,
一旦某一个1向前两位或者一位是1,那按照题目任意一台机器人不能在任意一台机器人的灌溉区域里,
这种状态就是不合法的。
dp[i][j][k]表示第i行状态为k,i-1行状态为j
把!((x&(x>>1))||(x&(x>>2))) == true的状态加起来 会发现最多只有60个
*/
#include<bits/stdc++.h>
using namespace std;
int mp[105]; //mp[i]的二进制表示每一行的H分布状况。
int cnt=0,state[105],sum[105]; //cnt表示状态总数,state[i]表示第i种状态,sum[i]表示第i种状态安装的大炮数量。
int dp[105][65][65];
bool ok(int x){
return !((x&(x>>1))||(x&(x>>2)));
}
int getsum(int x){ //x状态安装了多少门大炮,即x的二进制有几个1
int num=0;
while(x){
if(x&1) num++;
x>>=1;
}
return num;
}
void findstate(int n){ //预处理求出一共有多少种可能的状态。
for(int i=0;i<(1<<n);i++){
if(ok(i)){
state[++cnt]=i;
sum[cnt]=getsum(i);
}
}
}
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char ch;
cin>>ch;
if(ch=='H') mp[i]|=(1<<j-1);
}
}
findstate(m);
for(int i=1;i<=cnt;i++){
if(!(state[i]&mp[1])) dp[1][1][i]=sum[i];
}
for(int r=2;r<=n;r++){
for(int i=1;i<=cnt;i++){ //枚举第r行的状态。
if(state[i]&mp[r]) continue;
for(int j=1;j<=cnt;j++){ //枚举第r-1行状态
if(state[i]&state[j]) continue;
for(int k=1;k<=cnt;k++){//枚举第r-2行状态
if(state[i]&state[k]) continue;
dp[r][j][i]=max(dp[r][j][i],dp[r-1][k][j]+sum[i]);
}
}
}
}
int ans=0;
for(int i=1;i<=cnt;i++){
for(int j=1;j<=cnt;j++){
ans=max(ans,dp[n][i][j]);
}
}
cout<<ans<<endl;
return 0;
}