zoukankan      html  css  js  c++  java
  • POJ 3254 炮兵阵地(状态压缩DP)

    题意:由方格组成的矩阵,每个方格可以放大炮用P表示,不可以放大炮用H表示,求放最多的大炮,大炮与大炮间不会互相攻击。大炮的攻击范围为两个方格。

    分析:这次当前行的状态不仅和上一行有关,还和上上行有关,所以用三维dp【i】【j】【k】来表示第i行的状态为j,i-1行状态为k时最多的大炮。

    一开始看数据量为100 * 1024 * 1024 铁定要爆,但是由于大炮的攻击方式,单独看每一行最多只有几十种可行的状态,所以保存好这些状态就行了。


    #include <cstdio>
    #include <iostream>
    #include <cmath>
    #include <cstring>
    using namespace std;
    int n,m,sum;
    int dp[105][1 << 7][1 << 7]; // dp【i】【j】【k】来表示第i行的状态为j,i-1行状态为k时最多的大炮
    int buff[1 << 6]; // 存状态
    int bar[105];     // 存障碍 
    int num[1 << 6];  // 存每种状态中1的个数,即为大炮的个数
    char map[105][11];
    void init() {
        memset(bar,0,sizeof(bar));
        memset(dp,0,sizeof(dp));
        memset(buff,0,sizeof(buff));
        memset(num,0,sizeof(num));
        sum = 0;
    }
    void barrier() {
        for(int i=0; i<n; i++) {
            for(int j=0; j<m; j++) {
                if(map[i][j] == 'H') {
                    int move = m - j - 1;
                    bar[i] += (1 << move);
                }
            }
        }
    }
    
    bool judge(int s) {
        while(s) {
            if(s & 1) {
                if(((s >> 1) & 1) || ((s >> 2) & 1)) return false;
            }
            s = s >> 1;
        }
        return true;
    }
    
    void getbuff() {
        int total = 1 << m;
        for(int i=0; i<total; i++) {
            if(judge(i)) buff[sum++] = i;
        }
    }
    
    int cal(int s) {
        int cnt = 0;
        while(s) {
            if(s & 1) cnt ++;
            s = s >> 1;
        }
        return cnt;
    }
    
    void getnum() {
        for(int i=0; i<sum; i++) {
            num[i] = cal(buff[i]);
        }
    }
    int main() {
        scanf("%d%d",&n,&m);
        init();
        for(int i=0; i<n; i++) scanf("%s",map[i]);
        barrier();
        getbuff();
        getnum();
        for(int i=0; i<n; i++) {
            for(int j=0; j<sum; j++) {
                if(bar[0] & buff[j]) continue;
                for(int k=0; k<sum; k++) {
                    dp[0][j][k] = num[j];
                }
            }
        }
        for(int i=1; i<n; i++) {
            for(int j=0; j<sum; j++) {
                if(bar[i] & buff[j]) continue;
                for(int k=0; k<sum; k++) {
                    if(bar[i-1] & buff[k]) continue;
                    if((buff[j] & buff[k])) continue;
                    for(int l=0; l<sum; l++) {
                        if(i != 1) {
                            if(bar[i-2] & buff[l]) continue;
                            if(buff[k] & buff[l] || buff[j] & buff[l]) continue;
                        }
                        dp[i][j][k] = max(dp[i][j][k],
                                          dp[i-1][k][l] + num[j]);
                    }
                }
            }
        }
        int ans = 0;
        for(int i=0; i<n; i++) {
            for(int j=0; j<sum; j++) {
                for(int k=0; k<sum; k++) {
                    ans = max(ans,dp[i][j][k]);
                }
            }
        }
        printf("%d
    ",ans);
        return 0;
    }


  • 相关阅读:
    打印日志宏定义
    数据库读写操作
    SQL语句组成
    MySQL数据库的使用
    ubuntu下解决MySQL 1045 error
    css样式优先级
    redis
    dubbo
    maven
    Mybatis笔记
  • 原文地址:https://www.cnblogs.com/pangblog/p/3266637.html
Copyright © 2011-2022 走看看