Luogu P2704 [NOI2001] 炮兵阵地

P2704 NOI2001 炮兵阵地

思路

对于一行炮兵的分布,会产生影响的只有该行的地形以及前两行的炮兵分布。所以,我们可以使用状压DP,压缩前两行的分布讨论本行。

对于一行,我们可以预先处理出合法的分布,如果不做这一步,时间复杂度会过大。

正解

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

const int N = 105;
const int M = 15;

int n, m;
char ch[N][M];
int a[N];
int dp[N][1<<10][1<<10];

vector<int> mask[N];

inline bool check(int x) {
    vector<int> res;
    for(int i = m - 1; i >= 0; i--) {
        if(x >= (1 << i)) {
            res.push_back(m - i);
            x -= (1 << i);
        }
    }
    if(res.size() == 0) return true;
    for(int i = 0; i < res.size() - 1; i++) {
        if(res[i] + 2 >= res[i + 1]) 
            return false;
    }
    return true;
}

int main() {
    cin>>n>>m;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++) {
            cin>>ch[i][j];
            a[i] <<= 1;
            if(ch[i][j] == 'H') a[i] += 1;
        }
    for(int i = 1; i <= n; i++)
        for(int S = 0; S < (1 << m); S++)
            if(!(S & a[i]) && check(S)) {
                mask[i].push_back(S);
            }
    if(n == 1) {
        int maxn = 0;
        for(int i : mask[1])
            maxn = max(maxn, __builtin_popcount(i));
        cout<<maxn;
        return 0;
    }
    for(int i : mask[2]) {
        for(int j : mask[1])
            if(!(i & j)) {
                dp[2][i][j] = max(dp[2][i][j], __builtin_popcount(i) + __builtin_popcount(j));
        }
    }
    for(int i = 3; i <= n; i++) {
        for(int S1 : mask[i]) {
            for(int S2 : mask[i - 1]) {
                if(S1 & S2) continue;
                    for(int S3 : mask[i - 2]) {
                        if((S1 & S3) || (S2 & S3)) continue;
                        dp[i][S1][S2] = max(dp[i][S1][S2], dp[i-1][S2][S3] + __builtin_popcount(S1));
                    }
            }
        }
    }
    int ans = 0;
    for(int S1 : mask[n]) {
        for(int S2 : mask[n - 1]) {
            if((S2 & a[n - 1]) || !check(S2) || (S1 & S2)) continue;
            ans = max(ans, dp[n][S1][S2]);
        }
    }
    cout<<ans;
    return 0;
}
相关推荐
c238562 小时前
互斥锁高频面试题全解:从基础概念到底层实现,一文通关
java·c++·面试·职场和发展
nianniannnn2 小时前
c++复习自存--继承
开发语言·c++
kebidaixu2 小时前
两轮BMS 防打火策略详解
算法
wabs6663 小时前
关于动态规划【力扣1035.不相交的线和53.最大子数组和的思考】
算法·leetcode·动态规划
退休倒计时3 小时前
【每日一题】LeetCode 199. 二叉树的右视图 TypeScript
算法·leetcode·typescript
可编程芯片开发3 小时前
通过MATLAB实现PID控制器,积分分离控制器以及滑模控制器
算法
kebidaixu3 小时前
两轮BMS 短路保护策略详解
算法
王老师青少年编程3 小时前
2026年6月GESP真题及题解(C++二级):完全平方数计数
c++·题解·真题·gesp·二级·2026年6月·完全平方数计数
zwenqiyu3 小时前
非线性字符串数据结构串讲
数据结构·c++·学习·算法