解析:
经典状压DP
由于 m m 只有10,显然可以考虑状压。
而又有不能挨得太近的限制,显然我们可以直接预处理出可能存在的方案总数。
最后就是转移,首先合法状况才能转移,代码中用了checksol和checkcannon两个函数实现。
最后特殊处理一下一二行就行了。
代码:
#include<iostream>
#include<cstdio>
#include<cctype>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline
ll getint(){
re ll num=0;
re char c;
while(!isdigit(c=gc()));
while(isdigit(c))num=(num<<1)+(num<<3)+(c^48),c=gc();
return num;
}
inline
void outint(ll a){
static char ch[23];
if(a==0)pc('0');
while(a)ch[++ch[0]]=(a-a/10*10)^48,a/=10;
while(ch[0])pc(ch[ch[0]--]);
}
inline
bool checklegal(int j){
if((j&(j<<1))||(j&(j<<2)))return false;
return true;
}
inline int lowbit(int k){return k&-k;}
inline
int cntbit(int k){
int cnt=0;
while(k)++cnt,k-=lowbit(k);
return cnt;
}
int f[101][61][61];
int g[101];
int sta[61],tot;
int num[61];
int n,m;
inline
bool checksol(int i,int j){
return !(sta[i]&g[j]);
}
inline
bool checkcannon(int i,int j){
return !(sta[i]&sta[j]);
}
int main(){
n=getint();
m=getint();
for(int re i=0;i<(1<<m);++i){
if(checklegal(i))sta[++tot]=i,num[tot]=cntbit(i);
}
for(int re i=1;i<=n;++i){
string s;
cin>>s;
for(int re j=0;j<m;++j){
if(s[j]=='H')g[i]|=(1<<j);
}
}
for(int re i=1;i<=tot;++i){
if(checksol(i,1))
f[1][i][1]=num[i];
}
for(int re i=1;i<=tot;++i){
if(checksol(i,1))
for(int re j=1;j<=tot;++j){
if(checksol(j,2)&&checkcannon(i,j))
f[2][j][i]=f[1][i][1]+num[j];
}
}
for(int re i=3;i<=n;++i){
for(int re j=1;j<=tot;++j){
if(checksol(j,i))
for(int re k=1;k<=tot;++k){
if(checksol(k,i-1)&&checkcannon(k,j))
for(int re t=1;t<=tot;++t){
if(checksol(t,i-2)&&checkcannon(k,t)&&checkcannon(t,j))
f[i][j][k]=max(f[i][j][k],f[i-1][k][t]+num[j]);
}
}
}
}
int maxn=0;
for(int re i=1;i<=tot;++i)
for(int re j=1;j<=tot;++j)
maxn=max(maxn,f[n][i][j]);
cout<<maxn;
return 0;
}