状态压缩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> grid(n + 1, vector(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>> dp(2, vector<vector> (1 << m, vector(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> grid(n + 1, vector(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 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>> dp(2, vector<vector> (1 << m, vector(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

posted @ 2024-01-16 11:13  _Yxc  阅读(48)  评论(0)    收藏  举报