题目链接:

http://poj.org/problem?id=1185

炮兵阵地

Time Limit: 2000MS
Memory Limit: 65536K
#### 问题描述
> 司令部的将军们打算在`N*M`的网格地图上部署他们的炮兵部队。一个`N*M`的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:
> 如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。
> 现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。
>
#### 输入
> 第一行包含两个由空格分割开的正整数,分别表示N和M;
> 接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N 输出

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

####样例输入

5 4
PHPP
PPHH
PPPP
PHPP
PHHP

####样例输出

6

题解

第一感觉就是转移和前两行的状态有关,这样就变成2^20了,转移的时候会直接炸掉。

正解是,只记录有效的状态,这样发现一行有效的状态就60个,两行的也就3600,然后就可以直接按行转移了。

代码

  1. #include<map>
  2. #include<set>
  3. #include<cmath>
  4. #include<queue>
  5. #include<stack>
  6. #include<ctime>
  7. #include<vector>
  8. #include<cstdio>
  9. #include<string>
  10. #include<bitset>
  11. #include<cstdlib>
  12. #include<cstring>
  13. #include<iostream>
  14. #include<algorithm>
  15. #include<functional>
  16. using namespace std;
  17. #define X first
  18. #define Y second
  19. #define mkp make_pair
  20. #define lson (o<<1)
  21. #define rson ((o<<1)|1)
  22. #define mid (l+(r-l)/2)
  23. #define sz() size()
  24. #define pb(v) push_back(v)
  25. #define all(o) (o).begin(),(o).end()
  26. #define clr(a,v) memset(a,v,sizeof(a))
  27. #define bug(a) cout<<#a<<" = "<<a<<endl
  28. #define rep(i,a,b) for(int i=a;i<(b);i++)
  29. #define scf scanf
  30. #define prf printf
  31. typedef long long LL;
  32. typedef vector<int> VI;
  33. typedef pair<int,int> PII;
  34. typedef vector<pair<int,int> > VPII;
  35. const int INF=0x3f3f3f3f;
  36. const LL INFL=10000000000000000LL;
  37. const double eps=1e-9;
  38. const double PI = acos(-1.0);
  39. //start----------------------------------------------------------------------
  40. const int maxn=111;
  41. const int maxs=66;
  42. int n,m;
  43. ///存有效状态
  44. VI mysta;
  45. vector<LL> sumv;
  46. ///dp[cur][i][j]现在考虑前cur行,前1行状态是i,第cur行状态是j,能塞下的最多炮兵。
  47. LL dp[maxn][maxs][maxs];
  48. ///预处理出所有未冲突的状态
  49. void pre() {
  50. for(int i=0; i<(1<<10); i++) {
  51. int cnt=0;
  52. int mi=INF,pre=-100;
  53. for(int j=0; j<10; j++) {
  54. if(i&(1<<j)) {
  55. cnt++;
  56. if(mi>j-pre) mi=j-pre;
  57. pre=j;
  58. }
  59. }
  60. if(mi<=2) continue;
  61. mysta.pb(i);
  62. sumv.pb(cnt);
  63. }
  64. }
  65. char str[maxn][22];
  66. int tot;
  67. ///判断有没有吧炮搭到山上
  68. bool ok(int x,int i) {
  69. for(int j=0; j<m; j++) {
  70. if(!(x&(1<<j))) continue;
  71. if(str[i][j]=='H') {
  72. return false;
  73. }
  74. }
  75. return true;
  76. }
  77. ///判断上方冲突
  78. bool ok2(int pre,int cur) {
  79. for(int i=0; i<m; i++) {
  80. if((cur&(1<<i))==0) continue;
  81. if(pre&(1<<i)) return false;
  82. }
  83. return true;
  84. }
  85. ///特判只有一行的情况
  86. void solve1() {
  87. LL ans=0;
  88. for(int i=0; i<tot; i++) {
  89. if(ok(mysta[i],0)) ans=max(ans,sumv[i]);
  90. }
  91. prf("%lld\n",ans);
  92. }
  93. int main() {
  94. pre();
  95. while(scf("%d%d",&n,&m)==2&&n) {
  96. tot=upper_bound(all(mysta),(1<<m)-1)-mysta.begin();
  97. rep(i,0,n) scf("%s",str[i]);
  98. if(n==1) {
  99. solve1();
  100. continue;
  101. }
  102. ///预处理出前两行
  103. clr(dp,0);
  104. for(int i=0; i<tot; i++) {
  105. if(!ok(mysta[i],0)) continue;
  106. for(int j=0; j<tot; j++) {
  107. if(!ok(mysta[j],1)) continue;
  108. if(!ok2(mysta[i],mysta[j])) continue;
  109. dp[1][i][j]=sumv[i]+sumv[j];
  110. }
  111. }
  112. ///递推
  113. for(int cur=2; cur<n; cur++) {
  114. for(int k=0; k<tot; k++) {
  115. if(!ok(mysta[k],cur)) continue;
  116. for(int i=0; i<tot; i++) {
  117. if(!ok2(mysta[i],mysta[k])) continue;
  118. for(int j=0; j<tot; j++) {
  119. if(!ok2(mysta[j],mysta[k])) continue;
  120. dp[cur][j][k]=max(dp[cur][j][k],dp[cur-1][i][j]+sumv[k]);
  121. }
  122. }
  123. }
  124. }
  125. LL ans=0;
  126. for(int i=0; i<tot; i++) {
  127. for(int j=0; j<tot; j++) {
  128. ans=max(ans,dp[n-1][i][j]);
  129. }
  130. }
  131. prf("%lld\n",ans);
  132. }
  133. return 0;
  134. }
  135. //end-----------------------------------------------------------------------

Notes

当上帝关上一扇门的同时,会给你开启新的一扇门。
这题相比方格取数虽然状态变成两行了,但是有效的状态却变少了。

POJ 1185 炮兵阵地 状压dp的更多相关文章

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

    题目链接 POJ 1185 今天艾教留了一大堆线段树,表示做不动了,就补补前面的题.QAQ 这个题,我第一次写还是像前面HDU 2167那样写,发现这次影响第 i 行的还用i-2行那样,那以前的方法就 ...

  2. poj - 1185 炮兵阵地 状压DP 解题报告

    炮兵阵地 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 21553   Accepted: 8363 Description ...

  3. [poj 1185] 炮兵阵地 状压dp 位运算

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

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

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

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

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

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

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

  7. [POJ1185][NOI2001]炮兵阵地 状压DP

    题目链接:http://poj.org/problem?id=1185 很裸的状压,考虑对于一行用二进制储存每一种的状态,但是状态太多了做不了. 观察到有很多状态都是不合法的,于是我们预处理出合法的状 ...

  8. luogu 2704 炮兵阵地 状压dp

    状压的基础题吧 第一次看感觉难上天,后来嘛就.. 套路:先根据自身状态筛出可行状态,再根据地图等其他限制条件筛选适合的状态加入答案 f i,j,k 分别代表 行数,本行状态,上行状态,再累加答案即可 ...

  9. [NOI2001]炮兵阵地 状压DP

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

随机推荐

  1. PTA-BinarySearchTree BasicOperation

    /* 二叉查找树 基本操作 */#include <stdio.h> #include <stdlib.h> typedef int ElementType; typedef ...

  2. 20145209刘一阳《JAVA程序设计》第五周课堂测试

    第五周课堂测试 1.下列关于内部类的说法,正确的是(ABD) A .其他类不可以用某个类的内部类声明对象. B .内部类字节码文件的名字格式是"外嵌类名$内部类名". C .内部类 ...

  3. [COGS257]动态排名系统 树状数组套主席树

    257. 动态排名系统 时间限制:5 s   内存限制:512 MB [问题描述]给定一个长度为N的已知序列A[i](1<=i<=N),要求维护这个序列,能够支持以下两种操作:1.查询A[ ...

  4. 仙人掌&圆方树

    仙人掌&圆方树 Tags:图论 [x] [luogu4320]道路相遇 https://www.luogu.org/problemnew/show/P4320 [ ] [SDOI2018]战略 ...

  5. 6 开发工具IDE-pycharm

    http://www.cnblogs.com/sean-yao/p/8321034.html 激活码:http://blog.csdn.net/qq_39248703/article/details/ ...

  6. 07- django组件:中间件

    1.中间件的概念 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.因为改变的是全局,所以需要谨慎实用,用不好会影 ...

  7. 【CQOI2017】小Q的棋盘

    题面 题解 根据题意,不回头是最好的(显然法) \(dfs\)找到最长链,设长度为\(\mathrm{L}\),然后分类讨论: 如果\(\mathrm{L} > m\),答案就是\(m + 1\ ...

  8. 【linux】linux常用命令汇总

    linux主要的目录树的有/. /root. /home. /usr. /bin 等目录 / 根目录 /bin 存放必要的命令 /boot 存放内核以及启动所需的文件 /dev 存放设备文件 /etc ...

  9. jQuery插件编写基础之“又见弹窗”

    本文将通过一个实例来引出jQuery插件开发中的一些细节,首先介绍下jQuery插件开发的一些基础知识. jQuery的插件开发主要分为两类: 1. 类级别,即在jQuery类本身上扩展方法,类似与 ...

  10. Laya1.x Timer小记

    Timer是时钟管理类,在Laya初始化的时候会创建一个实例,通过Laya.timer访问. TimerHandler TimerHandler是对每一个定时任务的封装,每次调用frameOnce.f ...