题目

原题来自:\(NOI 2001\)

司令部的将军们打算在\(N*M\)

的网格地图上部署他们的炮兵部队。一个\(N*M\)的地图由\(N\)行\(M\)列组成,地图的每一格可能是山地(用 H表示),也可能是平原(用 P 表示)。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队),如果在地图中的灰色所标识的平原上部署一支炮兵部队,它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。其他位置攻击不到。炮兵的攻击范围不受地形的影响。现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。

输入格式

第一行包含两个由空格分割开的正整数,分别表示\(N\)和\(M\);

接下来的\(N\)行,每一行含有连续的\(M\)个字符(P 或者 H),中间没有空格。按顺序表示地图中每一行的数据。

输出格式

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

样例

样例输入

5 4

PHPP

PPHH

PPPP

PHPP

PHHP

样例输出

6

思路

这道题是一个很有趣的状压DP,由题意可知,对当前状态影响的有当前行状态,上一行状态,以及上上行的状态,对该行都有影响,所以,很显然我们枚举第\(i\)行,\(i-1\)行以及\(i-2\)的状态,对于任意一行(假设为\(i\)),那么我们对第\(i\)行进行合法化判断(仅对当前行),记录合法状态以及数目,方便下面枚举,还需要注意的是地图上的山地,需要单独开一个数组记录,与枚举状态求&,然后我们设\(F\)的三维数组,即\(F[i][j][k]\)代表第i行第j种状态从上一行第k种状态转移过来的最优解,所以有\(f[i][w][k]=max(f[i][w][k],f[i-1][k][j]+Q(w))\),\(f[i][w][k]\)上一状态为\(f[i-1][k][j]\),继承或求较大值更新

如果还是不明白的话,代码奉上



#include<bits/stdc++.h>
using namespace std;
const int maxn=1<<9;
int f[100+10][maxn][maxn];//第i行第j种状态从上一行第k种状态转移过来的最优解
int a[100+10];//记录地图山丘的数量
int state[maxn];//记录合法的状态
int tot,n,m;
int lowbit(int x){//求最低位1
return x&-x;
}
int Q(int x){//判断第x种合法状态下的炮兵个数
x=state[x];
int cnt=0;
for(int i=x;i;i-=lowbit(i))cnt++;
return cnt; } bool judge(int x){//判断状态x的合法性
if(x&(x<<1) || x&(x<<2))return 0;
return 1;
}
int main(){ cin>>n>>m;
char ch;
for(int i=1;i<=n;i++){
for(int j=0;j<m;j++){
scanf(" %c ",&ch);
if(ch=='H')a[i]+=(1<<j);//记录山丘位置
}
}
for(int i=0;i<(1<<m);i++){//记录合法状态
if(judge(i))state[++tot]=i;
}
for(int i=1;i<=tot;i++){//初始化第一行i种状态下的最优解,即为当前状态下的炮兵数量
if((a[1] & state[i])==0)f[1][i][1]=Q(i);
}
for(int i=2;i<=n;i++){//枚举第i行
for(int j=1;j<=tot;j++){//i-2行
if(state[j] & a[i-2])continue;//判断第i-2行
for(int k=1;k<=tot;k++){//枚举第i-1行
if(state[k] & a[i-1])continue;//判断第i-1行
if(state[k] & state[j])continue;//判断第i-1行与第i-2行
for(int w=1;w<=tot;w++){
if(state[w] & a[i])continue;//判断第i行
if(state[w] & state[k])continue;//判断第i行和第i-1行
if(state[w] & state[j])continue;//判断第i行和第i-2行
f[i][w][k]=max(f[i][w][k],f[i-1][k][j]+Q(w));//合法情况转移
}
}
}
}
int ans=0;
for(int i=1;i<=tot;i++){//求解
for(int j=1;j<=tot;j++){
if(a[n-1] & state[i])continue;
if(a[n] & state[j])continue;
if(state[i] & state[j])continue;
ans=max(f[n][j][i],ans);
}
}
cout<<ans<<endl; }

状压DP之炮兵阵地的更多相关文章

  1. dp乱写1:状态压缩dp(状压dp)炮兵阵地

    https://www.luogu.org/problem/show?pid=2704 题意: 炮兵在地图上的摆放位子只能在平地('P') 炮兵可以攻击上下左右各两格的格子: 而高原('H')上炮兵能 ...

  2. [状压dp]POJ1185 炮兵阵地

    中文题 题意不再赘述 对于中间这个“P” 根据dp的无后效性 我们只需考虑前面的 就变成了 只需考虑: 也就是状压前两行 具体与HDOJ的4539类似: 看HDOJ 4539 仅仅是共存状态的判断不同 ...

  3. 状压DP初识~~炮兵阵地

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

  4. POJ 1185 炮兵阵地(状压DP)

    炮兵阵地 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 26426   Accepted: 10185 Descriptio ...

  5. [poj1185]炮兵阵地_状压dp

    炮兵阵地 poj-1185 题目大意:给出n列m行,在其中添加炮兵,问最多能加的炮兵数. 注释:n<=100,m<=10.然后只能在平原的地方建立炮兵. 想法:第2到状压dp,++.这题显 ...

  6. TZOJ 4912 炮兵阵地(状压dp)

    描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P" ...

  7. POJ P1185 炮兵阵地 【状压dp】

    炮兵阵地 Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 29502 Accepted: 11424 Description 司令 ...

  8. 洛谷P2704 [NOI2001]炮兵阵地 [状压DP]

    题目传送门 炮兵阵地 题目描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图 ...

  9. POJ1185 炮兵阵地 —— 状压DP

    题目链接:http://poj.org/problem?id=1185 炮兵阵地 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions ...

随机推荐

  1. STL中常用算法

    一.排序 sort sort(first_pointer,first_pointer+n,cmp) 默认为升序 若要使用降序,自行写cmp 函数 bool cmp(int a,int b){ retu ...

  2. jsp页面用DBHelper实现简单的登陆验证

    首先我们需要写一个简单的登陆页面login.jsp,然后用from表单提交给index.jsp页面.在index.jsp页面通过DBHelper连接数据库判断账号和密码,如果密码正确则显示登陆成功. ...

  3. 原生js实现图片瀑布流布局,注释超详细

    完整代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...

  4. Promise相关学习

    what? Promise对象表示一个异步操作的最终状态(完成或失败),以及其返回的值 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/ ...

  5. 50道Java集合经典面试题(收藏版)

    前言 来了来了,50道Java集合面试题也来啦~ 已经上传github: https://github.com/whx123/JavaHome 1. Arraylist与LinkedList区别 可以 ...

  6. Linux系统管理——初学者建议

    学习Linux的注意事项(一) Linux严格区分大小写 Linux是严格区分大小写的,这一点和Windows不一样,所以操作时要注意区分大小写的不同,包括文件名和目录名.命令.命令选项.配置文件配置 ...

  7. 02.DRF-认识RESTful

    认识RESTful 在前后端分离的应用模式里,后端API接口如何定义? 例如对于后端数据库中保存了商品的信息,前端可能需要对商品数据进行增删改查,那相应的每个操作后端都需要提供一个API接口: POS ...

  8. 看到这些常见的android面试题,你慌了吗?

    最近参加了一些Android工程师岗位的面试,总结了一些常见的考点,希望能帮到正在面试的你(答案还在整理中)! 1.Java调用函数传入实际参数时,是值传递还是引用传递? 2.单例模式的DCL方式,为 ...

  9. 阿里云用smtp无法发送邮件

    无法发送邮件是因为什么网络协议的要求必须要封掉25端口,而这个解封的话弄了很长时间也没有弄开,所以就换了别的方法 这个的话我这块用的是PHPMailer 然后我把这个PHPMailer的配置文件里的 ...

  10. SpringMVC整合mybaitis

    目录 一.新建一个基于Maven的Web项目 二.创建数据库与表 三.添加依赖包 四.新建POJO实体层 五.新建MyBatis SQL映射层 六.完成Spring整合MyBatis配置 七.创建服务 ...