POJ 1185 炮兵阵地 状压dp
题目链接:
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,然后就可以直接按行转移了。
代码
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;
const int INF=0x3f3f3f3f;
const LL INFL=10000000000000000LL;
const double eps=1e-9;
const double PI = acos(-1.0);
//start----------------------------------------------------------------------
const int maxn=111;
const int maxs=66;
int n,m;
///存有效状态
VI mysta;
vector<LL> sumv;
///dp[cur][i][j]现在考虑前cur行,前1行状态是i,第cur行状态是j,能塞下的最多炮兵。
LL dp[maxn][maxs][maxs];
///预处理出所有未冲突的状态
void pre() {
for(int i=0; i<(1<<10); i++) {
int cnt=0;
int mi=INF,pre=-100;
for(int j=0; j<10; j++) {
if(i&(1<<j)) {
cnt++;
if(mi>j-pre) mi=j-pre;
pre=j;
}
}
if(mi<=2) continue;
mysta.pb(i);
sumv.pb(cnt);
}
}
char str[maxn][22];
int tot;
///判断有没有吧炮搭到山上
bool ok(int x,int i) {
for(int j=0; j<m; j++) {
if(!(x&(1<<j))) continue;
if(str[i][j]=='H') {
return false;
}
}
return true;
}
///判断上方冲突
bool ok2(int pre,int cur) {
for(int i=0; i<m; i++) {
if((cur&(1<<i))==0) continue;
if(pre&(1<<i)) return false;
}
return true;
}
///特判只有一行的情况
void solve1() {
LL ans=0;
for(int i=0; i<tot; i++) {
if(ok(mysta[i],0)) ans=max(ans,sumv[i]);
}
prf("%lld\n",ans);
}
int main() {
pre();
while(scf("%d%d",&n,&m)==2&&n) {
tot=upper_bound(all(mysta),(1<<m)-1)-mysta.begin();
rep(i,0,n) scf("%s",str[i]);
if(n==1) {
solve1();
continue;
}
///预处理出前两行
clr(dp,0);
for(int i=0; i<tot; i++) {
if(!ok(mysta[i],0)) continue;
for(int j=0; j<tot; j++) {
if(!ok(mysta[j],1)) continue;
if(!ok2(mysta[i],mysta[j])) continue;
dp[1][i][j]=sumv[i]+sumv[j];
}
}
///递推
for(int cur=2; cur<n; cur++) {
for(int k=0; k<tot; k++) {
if(!ok(mysta[k],cur)) continue;
for(int i=0; i<tot; i++) {
if(!ok2(mysta[i],mysta[k])) continue;
for(int j=0; j<tot; j++) {
if(!ok2(mysta[j],mysta[k])) continue;
dp[cur][j][k]=max(dp[cur][j][k],dp[cur-1][i][j]+sumv[k]);
}
}
}
}
LL ans=0;
for(int i=0; i<tot; i++) {
for(int j=0; j<tot; j++) {
ans=max(ans,dp[n-1][i][j]);
}
}
prf("%lld\n",ans);
}
return 0;
}
//end-----------------------------------------------------------------------
Notes
当上帝关上一扇门的同时,会给你开启新的一扇门。
这题相比方格取数虽然状态变成两行了,但是有效的状态却变少了。
POJ 1185 炮兵阵地 状压dp的更多相关文章
- POJ 1185炮兵阵地 (状压DP)
题目链接 POJ 1185 今天艾教留了一大堆线段树,表示做不动了,就补补前面的题.QAQ 这个题,我第一次写还是像前面HDU 2167那样写,发现这次影响第 i 行的还用i-2行那样,那以前的方法就 ...
- poj - 1185 炮兵阵地 状压DP 解题报告
炮兵阵地 Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 21553 Accepted: 8363 Description ...
- [poj 1185] 炮兵阵地 状压dp 位运算
Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用&quo ...
- POJ1185 炮兵阵地 —— 状压DP
题目链接:http://poj.org/problem?id=1185 炮兵阵地 Time Limit: 2000MS Memory Limit: 65536K Total Submissions ...
- TZOJ 4912 炮兵阵地(状压dp)
描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P" ...
- 洛谷P2704 [NOI2001]炮兵阵地 [状压DP]
题目传送门 炮兵阵地 题目描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图 ...
- [POJ1185][NOI2001]炮兵阵地 状压DP
题目链接:http://poj.org/problem?id=1185 很裸的状压,考虑对于一行用二进制储存每一种的状态,但是状态太多了做不了. 观察到有很多状态都是不合法的,于是我们预处理出合法的状 ...
- luogu 2704 炮兵阵地 状压dp
状压的基础题吧 第一次看感觉难上天,后来嘛就.. 套路:先根据自身状态筛出可行状态,再根据地图等其他限制条件筛选适合的状态加入答案 f i,j,k 分别代表 行数,本行状态,上行状态,再累加答案即可 ...
- [NOI2001]炮兵阵地 状压DP
题面: 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图.在每一格平原地形上最多 ...
随机推荐
- OO学习体会与阶段总结(多线程程序)
前言 在最近一个月的面向对象编程学习中,我们进入了编写多线程程序的阶段.线程的创建.调度和信息传递,共享对象的处理,线程安全类的编写,各种有关于线程的操作在一定程度上增加了近三次作业的复杂度与难度,带 ...
- TopJUI | easyui HTML Dialog页面间GET方式数据传递
较容易的方式通过URL内带参数进行数据传递 var url = "apddList.html?c0=" + row.uuid + "&c1=" + ro ...
- C语言 有关内存的思考题
非原创. 今天笔试时候遇到的问题,原文链接见底部. 1 void GetMemory(char *p) { p = (); } void Test(void) { char *str=NULL; Ge ...
- golang日志收集方案之ELK
每个系统都有日志,当系统出现问题时,需要通过日志解决问题 当系统机器比较少时,登陆到服务器上查看即可满足 当系统机器规模巨大,登陆到机器上查看几乎不现实 当然即使是机器规模不大,一个系统通常也会涉及到 ...
- Noip前的大抱佛脚----考场配置
(global-linum-mode t) (global-set-key (kbd "RET") 'newline-and-indent) (setq default-tab-w ...
- jQuery学习- 子选择器与可见性选择器
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 矩阵类的python实现
科学计算离不开矩阵的运算.当然,python已经有非常好的现成的库:numpy. 我写这个矩阵类,并不是打算重新造一个轮子,只是作为一个练习,记录在此. 注:这个类的函数还没全部实现,慢慢在完善吧. ...
- 3-[HTML]-head标签介绍
1.head标签 我们首先来介绍一下head标签的主要内容和作用,文档的头部描述了文档的各种属性和信息,包括文档的标题.编码方式及URL等信息,这些信息大部分是用于提供索引,辩认或其他方面的应用(移动 ...
- 【BZOJ1051】[HAOI2006]受欢迎的牛
[BZOJ1051][HAOI2006]受欢迎的牛 题面 bzoj 洛谷 题解 假如\(A\)喜欢\(B\)就连一条\(A\)到\(B\)的边 然后缩点,如果图不连通就\(Impossible\) 否 ...
- SSIS 处理错误的方法
Package在执行过程中,不可避免地会发生错误,如果处理错误?简单粗暴的做法,是Package直接停止运行.对于一个成熟的ETL工具,这显然不是唯一的错误处理方法.如果在数据流中出现错误,那么数据流 ...