状态压缩DP->炮兵阵地(Acwing)
https://www.acwing.com/problem/content/description/294/
题意:n,m平面内,有些格子可以放士兵,士兵的攻击范围是一个十字形,在士兵不攻击其他士兵的前提下,求方格内最多放置的士兵数。 n <= 100, m <= 10
分析:状压dp,状态是三维,dp[row][i][j]表示第row行以i排列放置,row - 1行以j排列放置的最多士兵数。 容易想到转移dp[row][i][j] <- dp[row - 1][j][k] 满足(i & j) == 0, (i & k) == 0, (k & j) == 0。在这种前提条件下,还要满足行((i <<(>>) 1(2)) & i) == 0。很容易列出枚举所有状态进行递推的代码:
void solve(){
int n, m;
cin >> n >> m;
vector<vector<char>> grid(n + 1, vector<char>(m + 1));
for (int i = 1; i <= n; ++i){
for (int j = 1; j <= m; ++j){
cin >> grid[i][j];
}
}
auto valid = [&](int x){
for (int j = 1; j <= 2; ++j){
if (((x >> j) & x) || ((x << j) & x)) {
return false;
}
}
return true;
};
auto cnt = [&](int row, int x)->int{
int res = 0;
for (int i = 0; i < m; ++i){
res += (((x >> i) & 1) && grid[row][i + 1] == 'P');
}
return res;
};
vector<vector<vector<int>>> dp(2, vector<vector<int>> (1 << m, vector<int>(1 << m)));
int cur = 1;
int ans = 0;
for (int row = 1; row <= n; ++row){
for (int i = 0; i < (1 << m); ++i){
if (valid(i)){
for (int j = 0; j < (1 << m); ++j){
if (valid(j) && ((i & j) == 0)){
if (row == 1){
dp[cur][i][j] = cnt(row, i);
ans = max(ans, dp[cur][i][j]);
continue;
}
int tmp = 0;
for (int k = 0; k < (1 << m); ++k){
if (valid(k) && (((i & k) == 0) && ((j & k) == 0))){
tmp = max(tmp, dp[cur ^ 1][j][k]);
}
}
dp[cur][i][j] = tmp + cnt(row, i);
ans = max(dp[cur][i][j], ans);
}
}
}
}
cur ^= 1;
}
cout << ans << '\n';
}
然而枚举所有状态的时间复杂度是pow(1 << 10, 3) ≈ 1e9
所以有一个优化的点就是直接剔除掉不合法的行状态,对于输入m,先枚举出所有合法的行状态,然后在合法的行状态中进行转移:
void solve(){
int n, m;
cin >> n >> m;
vector<vector<char>> grid(n + 1, vector<char>(m + 1));
for (int i = 1; i <= n; ++i){
for (int j = 1; j <= m; ++j){
cin >> grid[i][j];
}
}
auto valid = [&](int x){
for (int j = 1; j <= 2; ++j){
if (((x >> j) & x) || ((x << j) & x)) {
return false;
}
}
return true;
};
vector<int> valid_state;
for(int i = 0; i < (1 << m); ++i){
if (valid(i)){
valid_state.emplace_back(i);
}
}
auto cnt = [&](int row, int x)->int{
int res = 0;
for (int i = 0; i < m; ++i){
res += (((x >> i) & 1) && grid[row][i + 1] == 'P');
}
return res;
};
vector<vector<vector<int>>> dp(2, vector<vector<int>> (1 << m, vector<int>(1 << m)));
int cur = 1;
int ans = 0;
for (int row = 1; row <= n; ++row){
for (auto& i : valid_state){
for (auto& j : valid_state){
if ((i & j) == 0){
if (row == 1){
dp[cur][i][j] = cnt(row, i);
ans = max(ans, dp[cur][i][j]);
}
else{
int temp = 0;
for (auto& k : valid_state){
if (((i & k) == 0) && ((j & k) == 0)){
temp = max(temp, dp[cur ^ 1][j][k]);
}
}
dp[cur][i][j] = temp + cnt(row, i);
ans = max(ans, dp[cur][i][j]);
}
}
}
}
cur ^= 1;
}
cout << ans << '\n';
}
、
AC

浙公网安备 33010602011771号