用二进制数表示一行的状态
预处理记录满足条件的状态对应十进制数
因为当前行仅与上两行有关,所以状态转移方程为:
dp[i][k][t] = max(dp[i][k][t], dp[i-1][j][k]+num[t])
num[t]表示状态t对应的炮台数
dp[i][k][t]表示第i行状态为t,第i-1行状态为k时对应的最大值
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 100
using namespace std;
int m, n, top;
int dp[120][MAXN][MAXN];
int state[MAXN], num[MAXN];
int cur[120];
char str[MAXN];
bool ok(int x) {
if(x & (x<<1)) return 0;
if(x & (x<<2)) return 0;
return 1;
}
int count(int x) {
int cnt = 0;
while(x) {
++cnt;
x &= x-1;
}
return cnt;
}
void init() {
top = 0;
int total = 1<<n;
for(int i=0; i<total; ++i) {
if(ok(i)) {
state[++top] = i;
}
}
}
bool fit(int x, int k) {
if(x & cur[k]) return 0;
return 1;
}
int main(void) {
while(scanf("%d%d", &m, &n) != EOF && (m||n)) {
init();
for(int i=1; i<=m; ++i) {
cur[i] = 0;
scanf("%s", str);
for(int j=0; j<n; ++j) {
if(str[j] == 'H') {
cur[i] += 1<<j;
}
}
}
memset(dp, -1, sizeof(dp));
for(int i=0; i<=top; ++i) {
num[i] = count(state[i]);
//printf("state[%d] = %d\t %d\n", i, state[i], num[i]);
if(fit(state[i], 1))
dp[1][1][i] = num[i];
}
for(int i=2; i<=m; ++i) {
for(int t=1; t<=top; ++t) {
if(!fit(state[t], i))
continue;
for(int j=1; j<=top; ++j) {
if(state[t] & state[j])
continue;
for(int k=1; k<=top; ++k) {
if(state[k] & state[t])
continue;
if(dp[i-1][j][k] == -1)
continue;
dp[i][k][t] = max(dp[i][k][t], dp[i-1][j][k]+num[t]);
}
}
}
}
int ans = 0;
for(int i=1; i<=m; ++i) {
for(int j=1; j<=top; ++j)
for(int k=1; k<=top; ++k)
ans = max(ans, dp[i][j][k]);
}
printf("%d\n", ans);
}
return 0;
}