zoukankan      html  css  js  c++  java
  • poj1185(状态压缩DP)

    poj1185

    题意

    给出字母矩阵,只能在字母为 P 的位置放置大炮,

    如图所示,每个大炮的射程固定,现在要求尽可能多的放大炮,且使得每个大炮都不在其它大炮的射程内。问最多能放多少。

    分析

    poj3254
    很类似的一道题,但是注意到这道题,放置一个大炮后,不仅影响到与之相邻的下一行,同时对下下一行产生影响,也就是说某一个地点能否存在大炮,取决于它上面两行的状态,那么状态的转移就和上面两行有关,两层循环枚举上面两层的可行状态,判断加上这一层的状态后是否合法(即对于连续的 3 行,每一列最多只能存在一个 1),如果合法,加上这个状态下在这一行最多能放大炮的数量,不断更新最大值。
    可以预处理一行的状态,求得同时在这一行最多放几个大炮。

    code

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<string>
    using namespace std;
    typedef long long ll;
    const int MAXN = (1 << 10) + 10;
    int dp[105][MAXN][MAXN];
    int num[1 << 10];
    string str;
    bool check(int j, int s) { // 判断 j 是否是一个可行状态
        return (j | s) == s && (j & (j >> 1)) == 0
                            && (j & (j >> 2)) == 0;
    }
    void F(int n) {
        vector<int> v;
        if(!n) cout << 0;
        while(n) {
            v.push_back(n & 1);
            n /= 2;
        }
        for(int i = v.size() - 1; i >= 0; i--) {
            cout << v[i];
        }
    
    }
    int main() {
        int n, m;
        cin >> n >> m;
        for(int i = 0; i < (1 << m); i++) {
            int k = 0;
            for(int j = 0; j < 11; j++) {
                if(!k) {
                    if((i >> j) & 1) {
                        k = 3;
                        num[i]++;
                    } else k = 1;
                }
                k--;
            }
        }
        vector<int> vec1, vec2, vec3; // vec2存上一层的可行状态,vec1存上上一层的可行状态
        int ans = 0;
        for(int i = 0; i < n; i++) {
            cin >> str;
            int s = 0;
            for(int j = 0; j < m; j++) {
                if(str[j] == 'P') {
                    s |= (1 << j);
                }
            }
            if(i > 1) {
                vec3.clear();
                for(int j = 0; j < (1 << m); j++) {
                    if(check(j, s)) {
                        for(int v = 0; v < vec1.size(); v++) {
                            for(int e = 0; e < vec2.size(); e++) {
                                if((j & vec1[v]) == 0 && (j & vec2[e]) == 0 && (vec1[v] & vec2[e]) == 0) { // 保证连续 3 行每一列最多只有一个 1
                                    dp[i][j][vec2[e]] = max(dp[i][j][vec2[e]], dp[i - 1][vec2[e]][vec1[v]] + num[j]);
                                    ans = max(ans, dp[i][j][vec2[e]]);
                                }
                            }
                        }
                        vec3.push_back(j);
                    }
                }
                vec1 = vec2;
                vec2 = vec3;
            } else if(!i) {
                for(int j = 0; j < (1 << m); j++) {
                    if(check(j, s)) {
                        dp[i][j][0] = num[j];
                        ans = max(ans, num[j]);
                        vec1.push_back(j);
                    }
                }
            } else {
                for(int j = 0; j < (1 << m); j++) {
                    if(check(j, s)) {
                        for(int k = 0; k < vec1.size(); k++) {
                            if((j & vec1[k]) == 0) {
                                dp[i][j][vec1[k]] = dp[i - 1][vec1[k]][0] + num[j];
                                ans = max(ans, dp[i][j][vec1[k]]);
                            }
                        }
                        vec2.push_back(j);
                    }
                }
            }
        }
        cout << ans << endl;
        return 0;
    }
    
  • 相关阅读:
    eclipse本地覆盖版本库
    数据库表分区
    oracle监听器启动,实例启动
    Mac 终端命令大全
    Mac基本用法
    wen前端学习计划
    css3animation模仿百度音乐的唱片旋转效果
    获取HTML DOM节点元素的方法的总结
    简单CSS技巧实现的Logo动画效果(很像导航栏上经常运用的效果,但有差别)
    详解 CSS 属性
  • 原文地址:https://www.cnblogs.com/ftae/p/7009065.html
Copyright © 2011-2022 走看看