炮兵阵地
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 32802   Accepted: 12650

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

Source

 
题意:
有一个n*m的格子有的格子是山,有的格子是平原。只有平原可以放一个炮兵。炮兵的攻击范围是两格,也就是说如果一个格子放了炮兵,他上下左右两格里不能再放炮兵。问这样n*m的地图中,可以最多放多少炮兵。
 
思路:
因为m是小于10的,每个格子又只有放或者不放的状态。所以我们可以考虑状压。用一个十进制数来表示某一行的放炮兵状态。第j位是1表示第j列的格子放了炮兵,0表示没有放。同理,地图上一行的山或是平原的状态也可以用十进制数来表示。
以行数i作为状态转移的阶段,转移的时候需要看的是前面两行的状态。用dp[i][j][k]表示第i行的状态时j,第i-1行的状态是k时,前i行最多的炮兵数。
显然dp[i][j][k] = max(dp[i -1][k][l]) + j的二进制表示中1的个数
并且并不是所有0~2^m-1的数都是可行的,必须要是二进制中1之间的间隔大于等于2的数才可以。
那么我们就可以首先预处理出所有可行的数,每次遍历这些数就可以了。对于每一行还需要去判断一下是否满足当前的地图状态。
刚开始用把平原当1,山当0,这样判断的时候位运算会有点麻烦。所以后面改成了用山当1,这样只需要用& == 0就可以了。
debug了超级久,今天终于找到bug了,太菜了。码力堪忧......
 #include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <cstring> using namespace std;
typedef long long LL;
#define inf 0x3f3f3f3f const int maxn = ;
int n, m, mostm;
int dp[maxn][][], dixing[maxn];
int cntone[], S[], cnt; bool valid(int i, int x)
{
if (dixing[i] & x)return false;
else return true;
} int get_one(int x)
{
int res = ;
while (x) {
res += (x & );
x >>= ;
}
return res;
} bool ok(int x)
{
if (x & (x << ))return false;
if (x & (x << )) return false;
return true;
} void getS()
{
cnt = ;
mostm = << m;
for (int i = ; i < mostm; i++) {
if (ok(i)) {
S[cnt] = i;
cntone[cnt] = get_one(i);
cnt++;
}
}
} int main()
{
while (scanf("%d%d", &n, &m) != EOF) {
getS();
memset(dixing, , sizeof(dixing));
for (int i = ; i <= n; i++) {
char tmp[];
scanf("%s", tmp);
//printf("%s", tmp + 1);
for (int j = ; j < m; j++) {
//cout<<tmp[j]<<endl;
if (tmp[j] == 'H') {
dixing[i] |= ( << (m - - j));
}
}
} memset(dp, -, sizeof(dp));
dp[][][] = ;
int ans = ;
for (int j = ; j < cnt; j++) {
if (valid(, S[j])) {
dp[][j][] = cntone[j];
ans = max(ans, dp[][j][]);
}
}
//cout<<1<<" "<<ans<<endl; for (int i = ; i <= n; i++) {
int tiaoshi = -;
for (int j = ; j < cnt; j++) {
if (valid(i, S[j])) {
for (int k = ; k < cnt; k++) {
if (valid(i - , S[k]) && (S[j] & S[k]) == ) {
int mmm = -;
for (int l = ; l < cnt; l++) {
if (valid(i - , S[l]) && dp[i - ][k][l] != - && (S[j] & S[l]) == ) {
mmm = max(mmm, dp[i - ][k][l]);
}
}
//cout<<i - 1<<" "<<mmm<<endl;
dp[i][j][k] = max(dp[i][j][k], mmm + cntone[j]);
tiaoshi = max(tiaoshi, dp[i][j][k]);
if (i == n)ans = max(ans, dp[i][j][k]);
}
}
}
}
//cout<<i<<" "<<tiaoshi<<endl;
}
printf("%d\n", ans);
} //return 0;
}

poj1185 炮兵阵地【状压DP】的更多相关文章

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

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

  2. poj1185 炮兵阵地 状压dp

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

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

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

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

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

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

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

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

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

  7. luogu 2704 炮兵阵地 状压dp

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

  8. POJ 1185 炮兵阵地 状压dp

    题目链接: http://poj.org/problem?id=1185 炮兵阵地 Time Limit: 2000MS Memory Limit: 65536K 问题描述 司令部的将军们打算在N*M ...

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

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

  10. 炮兵阵地 /// 状压DP oj26314

    题目大意: 炮兵阵地 设置炮兵的位置 其上两位 下两位 左两位 右两位 不能同时设置炮兵 这题是 corn fields玉米地 的升级版 可以先看下这题的注释 更详细些 第一种方法是网上大多数题解的解 ...

随机推荐

  1. 在不指定特殊属性的情况下,哪几种HTML标签可以手动输入文本:()

    A. <TEXTAREA></TEXTAREA> B. <INPUT type=”text”/> C. <INPUT type=”hidden”/> D ...

  2. 转载:【原译】Erlang性能的八个误区(Efficiency Guide)

    转自:http://www.cnblogs.com/futuredo/archive/2012/10/16/2725770.html The Eight Myths of Erlang Perform ...

  3. ScreenPointToRay - 近视口到屏幕的射线

    正如题目所说,ScreenPointToRay可以计算从Camera的近视口nearClip向前发射一条射线到屏幕上的点的坐标. 函数原型为: public Ray ScreenPointToRay( ...

  4. 二分求幂,快速求解a的b次幂

    一个引子 如何求得a的b次幂呢,那还不简单,一个for循环就可以实现! void main(void) { int a, b; ; cin >> a >> b; ; i < ...

  5. xml的序列化与反序列化求一个好用的东西,类似,newtonsoft.net转json的东西。xml里面的结构和数据库不一致..................

    xml的序列化与反序列化求一个好用的东西,类似,newtonsoft.net转json的东西.xml里面的结构和数据库不一致..................

  6. bootstrap+PHP表单验证

    来源:http://www.sucaihuo.com/php/1814.html demo http://www.sucaihuo.com/jquery/18/1814/demo/

  7. Ubuntu 10.04 安装 Oracle11gR2

    注意点: 在 ubuntu的 /bin 下建立以下几个基本命令的链接: /bin/basename->/usr/bin/basename /bin/awk->/usr/bin/gawk / ...

  8. 【转】VS2008快速将代码中字符串改为_T(“”)风格的方法

    用VC在修改一些老程序的时候,经常面临“UNICODE化”的工作.就是将一些传统C语言风格的字符串,如“string”,改为既能够通过多字节编码工程编译,又能通过UNICODE工程编译的代码,即形如_ ...

  9. linux用户态定时器的使用---19

    原创博文,转载请标明出处--周学伟http://www.cnblogs.com/zxouxuewei/ linux操作系统为每一个进程提供了3个内部计时器. ITIMER_REAL;ITIMER_VI ...

  10. 0060 Spring MVC的数据类型转换--ConversionService--局部PropertyEditor--全局WebBindingInitializer

    浏览器向服务器提交的数据,多是字符串形式,而有些时候,浏览器需要Date.Integer等类型的数据,这时候就需要数据类型的转换器 使用Spring的ConversionService及转换器接口 下 ...