题目传送门:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int m,n;
int dp[2][1<<11][1<<11],f[110];//滚动数组dp[i][j][k],j为上一行的状态k为上两行的状态,f数组为储存每行的地形状态
int cnt[1<<11];//每一行的炮台树木
vector <int> state;//储存每一行的可行状态
bool chack(int x)//判断是否合法
{
for(int i=0;i<m;i++)
if((x>>i&1)&&((x>>i+1&1)||(x>>i+2&1)))
return false;
return true;
}
int cnts(int x)//储存每行的炮台个数
{
int res=0;
while(x)
{
res+=x&1;
x>>=1;
}
return res;
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
char a;
cin>>a;
if(a=='H')
f[i]+=1<<j;//储存每行地形状态
}
}
for(int i=0;i<(1<<m);i++)
{
if(chack(i))
{
state.push_back(i);//储存可行方案
cnt[i]=cnts(i);//计数
}
}
//cout<<state.size()<<endl;
for(int i=0;i<n+2;i++)
for(int j=0;j<state.size();j++)//第i-2行的状态
for(int u=0;u<state.size();u++)//第i-1行的状态
for(int k=0;k<state.size();k++)//第i行的状态
{
int a=state[u],b=state[j],c=state[k];
if((a&b)||(a&c)||(b&c))//范围内不能有其他炮台
continue;
if(f[i]&c) continue;//确定炮台一定在平原
dp[i&1][j][k]=max(dp[i&1][j][k],dp[(i-1)&1][u][j]+cnt[c]);//状态转移,本状态等于上一行的状态加本行的炮台数
}
cout<<dp[(n+1)&1][0][0]<<endl;//结果为所需行的下一行的不放任何炮台的数量
return 0;
}