You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

64 lines
2.5 KiB

2 years ago
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
const int M = 1 << 10;
int n, m; // n行m列n<=100,m<=10,注意状态压缩DP对列的长度很敏感太大不行
int g[N]; // 记录每一列的山地情况是一个二进制标识转化后的十进制数最大就是全都是1也就是2^m-1
int cnt[M];
int f[N][M][M];
vector<int> st;
vector<int> head[M];
// 检查一个状态是不是合法状态[同一行必须隔两个及两个以上才是安全的]
bool check(int x) {
return !(x & x >> 1 || x & x >> 2);
}
// 统计某个状态中数字1的数量
int count(int s) {
int res = 0;
for (int i = 0; i < m; i++) // 遍历每一列
if (s >> i & 1) res++; // 如果此个位置数字是1那么总的数量++
return res;
}
int main() {
// 输入
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) // n行
for (int j = 1; j <= m; j++) { // m列
char c;
scanf(" %c", &c); // 注意scanf输入char的时候前面要加一个空格
if (c == 'H') g[i] += 1 << (j - 1); // 山地上不能够部署炮兵部队
}
// 1、预处理所有合法状态[单行合法即可]
for (int i = 0; i < 1 << m; i++)
if (check(i)) st.push_back(i), cnt[i] = count(i); // 预算出每个状态i里有多少个数位是1
// 2、找出所有合法状态的合法转移[行间状态兼容检测]
for (int a : st)
for (int b : st)
if (!(a & b)) // 上下行间不能存在同列的1
head[a].push_back(b);
// 3、dp
for (int i = 1; i <= n; i++) // 枚举每一行
for (int a : st) { // 枚举i行的每个状态
if (g[i] & a) continue; // 按i这样摆确实是本行内不冲突但如果准备放大炮的位置是高地是不行的。
for (int b : head[a]) // 枚举第i-1行的每个可能状态,b肯定与a不冲突
for (int c : head[b]) // 枚举第i-2行的每个可能状态,c肯定是与b不冲突的
if (!(a & c)) // 如果c也与a不冲突的话,才是三行间完全兼容的方案
f[i][a][b] = max(f[i][a][b], f[i - 1][b][c] + cnt[a]);
}
// 4、枚举最终的状态最大值
int res = 0;
for (int a : st)
for (int b : head[a])
res = max(res, f[n][a][b]);
// 5、输出
printf("%d\n", res);
return 0;
}