zoukankan      html  css  js  c++  java
  • 状压DP初识~~炮兵阵地

    炮兵阵地
    Time Limit: 2000MS   Memory Limit: 65536K
    Total Submissions: 31718   Accepted: 12253

    Description

    司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 

    如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。 
    现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。 

    Input

    第一行包含两个由空格分割开的正整数,分别表示N和M; 
    接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。

    Output

    仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。

    Sample Input

    5 4
    PHPP
    PPHH
    PPPP
    PHPP
    PHHP

    Sample Output

    6

    题意:中文题面,题意很明显了
    我们来考虑一下最暴力的搜索每个点都尝试一遍的话会是1000!
    肯定是会爆炸的,所以,既然每行的列数在10以内,那么我们很自然的就想到了状态压缩的dp

    将每一行的状态存储为一个二进制数,1表示可以放,0表示不能放
    每一层的状态由上一层推导而来,如果上层这个地方放了,那么下面的这个地方就不能放
    所以我们要用到二进制的位运算

    dp[r][j][i]=max(dp[r1][k][j]+sum[i])

    其中sum[i]sum[i]为i状态对应的数量

    代码如下:

    (参考上海全能王博客

    http://cubercsl.cn/solve/2017-summer/emplacement/

    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <vector>
    #include <set>
    #include <map>
    #include <cmath>
    #include <queue>
    #include <stack>
    using namespace std;
    const int maxn =105;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9+7;
    const double eps = 1e-6;
    int dp[maxn][maxn][maxn];
    int maze[maxn];
    vector<int> v,sum;
    inline bool ok(int s){
      return !(s&(s<<1))&&!(s&(s<<2));
    }
    inline int getsum(int s){
      int ret=0;
      for(;s;s>>=1){
        if(s&1) ret++;
      }
      return ret;
    }
    void init(int m){
      for(int i=0;i <(1<<m);i++){
        if(ok(i)){
          v.push_back(i);
          sum.push_back(getsum(i));
        }
      }
    }
    int main(){
        int n,m;
        char tmp;
        cin>>n>>m;
        init(m);
        memset(dp,0xc0,sizeof(dp));
        for(int i=0;i<n;i++){
          for(int j=0;j<m;j++){
            cin>>tmp;
            if(tmp=='H') maze[i]|=(1<<j);
          }
        }
        for(int i=0;i<v.size();i++){
          if(!(v[i]&maze[0])){
            dp[0][0][i]=sum[i];
          }
        }
        for(int r=1;r<n;r++)
          for(int i=0;i<v.size();i++)
            if(!(v[i]&maze[r]))
              for(int j=0;j<v.size();j++)
                if(!(v[i]&v[j]))
                  for(int k=0;k<v.size();k++)
                    if(!(v[i]&v[k]))
                      dp[r][j][i]=max(dp[r][j][i],dp[r-1][k][j]+sum[i]);
        int ans=0;
        for(int i=0;i<v.size();i++){
          for(int j=0;j<v.size();j++){
            ans=max(ans,dp[n-1][i][j]);
          }
        }
        cout<<ans<<endl;
        return 0;
    }
     
    每一个不曾刷题的日子 都是对生命的辜负 从弱小到强大,需要一段时间的沉淀,就是现在了 ~buerdepepeqi
  • 相关阅读:
    Python——五分钟带你弄懂迭代器与生成器,夯实代码能力
    LeetCode37 使用回溯算法实现解数独,详解剪枝优化
    LeetCode 33,在不满足二分的数组内使用二分的方法
    丰富图文详解B-树原理,从此面试再也不慌
    看完这篇让你高数不挂科之——泰勒公式
    数据结构——动手实战双向链表
    你听说过JMX么
    【网络安全】CSRF攻击详解
    【开发工具】本机安装的JDK8,启动IDEA2019没反应
    Java开发过程中的常用工具类库
  • 原文地址:https://www.cnblogs.com/buerdepepeqi/p/9357189.html
Copyright © 2011-2022 走看看