#include <bits/stdc++.h>
using namespace std;
using VI = vector<int>;
using PII = pair<int,int>;
using ll = long long;
using ull = unsigned long long;
int n,m;
int f[2][1024][1024];
int mp[110];
int v[2000][2000];
int stct[2000];
bool check(int x){
if(!(x & x>>1) && !(x & x>>2)){
return true;
}
return false;
}
int count_1(int x){
int res = 0;
while(x){
res += (x&1);
x = x >> 1;
}
return res;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
int st = 0;
for(int j=0;j<m;j++){
char x;
cin>>x;
if(x == 'H') st |= 1 << j;
}
mp[i] = st;
}
vector<int>st;
// 1 << m -1 是前m-1位的所有情况
for(int i=0;i<=(1<<m)-1;i++){
if(check(i)) st.push_back(i),stct[i] = count_1(i);
}
VI head[1<<m];
for(auto st1 :st){
for(auto st2 : st){
if( !(st1 & st2)){
head[st1].push_back(st2);
}
}
}
memset(f,-0x3f,sizeof f);
f[0][0][0] = 0;
for(int i=1;i<=n;i++)
{
int cur = i & 1;
int pre = (i-1) & 1;
for(auto x : st)
{
if(!(x & mp[i]))
{
for(auto y : head[x])
{
for(auto z :head[y])
{
if(!(z & x))
{
f[cur][x][y] = max(f[cur][x][y],f[pre][y][z] + stct[x]);
}
}
}
}
}
}
ll res= 0;
for(int x :st){
for(int pre : head[x]){
res = max(res,(ll)f[n&1][x][pre]);
}
}
cout<<res;
}
感觉线性状压并不是难思考,而是对于状态的预处理是一个难点,
线形状压一般都是以层做转移状态(大概
对于这题
考虑到第i行能否转移区间与第 i - 1 行 和 第 i-2 行的同一列是否放了炮兵,
如果只假设了当前行的状态发f[i][j] 很难写出一个状态转移方程
如 f[i-1][k] 可以到 f[i][j] f[i-2][j] 转移到f[i-1][k] 但f[i-2][j] 和 f[i][j] 很明显不太对头
所以开三维f[i][j][k];