解题思路:
简单的状压DP,1表示放炮,预处理出每一行所有两个1间隔不小于2的状态,每一行的状态只和上面两行有关,因此可以枚举这三行的状态,用DP[i][j][k]表示第i行状态为k,第i-1行状态为j的数目,转移方程为dp[i][j][k] = max(dp[i][j][k], dp[i-1][l][j] +count(k));
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <map>
#define LL long long
#define FOR(i, x, y) for(int i=x;i<=y;i++)
using namespace std;
const int MAXNr = 100 + 10;
const int MAXNc = (1 << 11);
int dp[MAXNr][MAXNr][MAXNr];
int C[MAXNr], state[MAXNc];
char str[MAXNr][MAXNr];
int Map[MAXNr];
int N, M, K;
bool judge(int x)
{
if(x & (x << 1)) return false;
if(x & (x << 2)) return false;
return true;
}
int count(int x)
{
int res = 0;
while(x)
{
if(x & 1) res++;
x >>= 1;
}
return res;
}
void init()
{
memset(Map, 0, sizeof(Map));
int r = (1 << M) - 1; K = 0;
FOR(i, 0, r) if(judge(i))
state[++K] = i;
memset(dp, -1, sizeof(dp));
}
int main()
{
while(scanf("%d%d", &N, &M)!=EOF)
{
if(N == 0 && M == 0) break;
init();
FOR(i, 1, N) scanf("%s", str[i]+1);
FOR(i, 1, N)
FOR(j, 1, M) if(str[i][j] == 'H')
Map[i] = (Map[i] | (1 << (M - j)));
FOR(i, 1, K) if(!(state[i] & Map[1]))
{
dp[1][1][i] = count(state[i]);
}
FOR(i, 2, N)
{
FOR(l, 1, K)
{
if(state[l] & Map[i]) continue;
FOR(j, 1, K)
{
if(state[l] & state[j]) continue;
FOR(t, 1, K)
{
if(state[l] & state[t]) continue;
if(dp[i-1][t][j] == -1) continue;
dp[i][j][l] = max(dp[i][j][l], dp[i-1][t][j] + count(state[l]));
}
}
}
}
int ans = 0;
FOR(i, 1, N)
FOR(j, 1, K)
FOR(k, 1, K)
ans = max(ans , dp[N][j][k]);
printf("%d\n", ans);
}
return 0;
}