题目链接
因为m <= 10,考虑状压DP
先dfs搜出所有可能状态
f[i][j][k] 表示上上行是 i, 上行是 j, 第 k 行取得的最大值
但如果直接开满数组,MLE
考虑滚动数组
此题只需保留2个状态,上上行,上行
所以用四层循环枚举——超时
考虑剪枝
放进上上行时先与题述条件对比
放入上行是与上上行和题述条件进行比较
。。。。。。
因为这个DP数组单调递增,不用担心之前的发生冲突,不放心可以开一个used数组
最后输出,312ms,不慢
#include<bits/stdc++.h>
using namespace std;
const int N = 1 << 10 | 1;
int f[N][N][3]; // f[i][j][k] 表示上上行是 i, 上行是 j, 第 k 行取得的最大值
int g[N], v[N];
int o[101];// 每一行本身的限制
int tot = 0;
int n, m;
void dfs(int u, int now, int cur) {
if(u > m) {
g[++tot] = now;
v[tot] = cur;
return;
}
dfs(u + 1, now, cur);
dfs(u + 3, now + (1 << (u - 1)), cur + 1);
}
int main() {
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
char c;
cin >> c;
if(c == 'H') o[i] += 1 << (j - 1);
}
}
dfs(1, 0, 0);
for(int i = 1; i <= tot; i++) {
if((g[i] & o[1]) == 0) {
f[0][g[i]][1] = v[i];
}
}
for(int i = 2; i <= n; i++) {
for(int j = 1; j <= tot; j++) {// 上上行可能的放置方法
if(g[j] & o[i - 2]) continue;
for(int l = 1; l <= tot; l++) {// 上行可能的放置方法
if((g[l] & o[i - 1]) || (g[l] & g[j])) continue;
for(int k = 1; k <= tot; k++) {
if((g[k] & o[i]) || (g[k] & g[j]) || (g[k] & g[l])) continue;
f[g[l]][g[k]][i % 3] = max(f[g[l]][g[k]][i % 3], f[g[j]][g[l]][(i - 1) % 3] + v[k]);
}
}
}
}
int ans = 0;
for(int i = 1; i <= tot; i++) {
for(int j = 1; j <= tot; j++) {
/*for(int l = 1; l <= 2; l++) {
printf("f[%d][%d][%d] = %d, ", g[i], g[j], l, f[g[i]][g[j]][l]);
}*/
ans = max(ans, f[g[i]][g[j]][n % 3]);
}
}
printf("%d", ans);
return 0;
}