印象中这道题好像我曾经肝过,但是没肝出来,现在肝出来了也挺开心的

题目链接:http://poj.org/problem?id=1185

Time Limit: 2000MS Memory Limit: 65536K

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

题解:

感谢博文http://www.cnblogs.com/scau20110726/archive/2013/02/27/2935256.html,可以说讲的非常清晰了;

首先,一个炮的攻击范围有两格,所以对于第i行来讲,i-1行和i-2行对它有影响,i-3行及以上的都没有影响了;

所以我们要去求得到关于第i行的一些信息,只需要知道i-1和i-2的信息即可;

然后考虑表示地图:

  山用1表示,空地用0表示;那么对于一行,就是一个0 or 1的串,这是个二进制数,可以状压成一个十进制数;

再考虑表示一行上部署炮兵部队的状态:

  只考虑一行上,能不能放炮的话,状态最大达到 (1<<10) - 1 = 2^10 -1;

  但是实际上,因为炮与炮之间不能相互攻击的限制,状态数没有那么多;

  假设一个状态i,如果满足 (i&(i<<1)) == 0 && (i&(i<<2)) == 0 的话,它才是一个符合炮与炮之间相互不能攻击的状态;

  由此,我们通过枚举计算一下到底有多少状态:

for(int i=;i<=(<<10)-;i++) if( (i&(i<<))== && (i&(i<<))== ) cnt++;

  程序运行得到的cnt等于60,所以我们可以知道,最大的状态数不会超过60;

  由此使用一个state[]数组保存状态(依然状压成十进制数),把每次枚举出来可行的状态保存进去;

并且值得一提的是,我们把state定义成结构体数组:

  state[i].sta:表示第i个状态时怎么样的;

  state[i].cnt:记录这个状态下,部署了多少炮兵部队;

这样一来,方便后续操作,也不容易出错,在枚举求得所有可行状态时,也可以一并求出cnt;

那么怎么判断炮兵部队不在山上呢?  只要state[i] & mp[r] == 0 ,就表示state[i]这个状态,可以放在r这行上,而且炮不会在山上,炮之间也不会攻击;

那么又如何判断 i行,i-1行,i-2行的炮没有冲突呢?所以我们假设现在i行,i-1行,i-2行的炮的摆放情况分别是state[i],state[j],state[k];

当满足 state[i] & state[j] == 0   state[i] & state[k] == 0     state[j] & state[k] == 0 条件时,三行的部署情况没有冲突;

最后的状态转移方程,可以直接参考代码中的状态转移过程;

AC代码:

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 103
#define MAXM 11
using namespace std;
int n,m;
int mp[MAXN]; int state_num;
struct State{
int sta,cnt;
}state[]; int dp[MAXN][][]; int main()
{
scanf("%d%d",&n,&m); for(int i=;i<=n;i++)
{
mp[i]=;
char input[];
scanf("%s",input+);
for(int j=;j<=m;j++)
{
int tmp=((input[j]=='H')?:);
mp[i]|=tmp;
if(j!=m) mp[i]=mp[i]<<;
}
}//二进制记录地图 state_num=;
for(int i=;i<=(<<m)-;i++)
{
if( (i&(i<<))== && (i&(i<<))== )
{
state_num++;
state[state_num].sta=i; state[state_num].cnt=;
for(int tmp=i;tmp;tmp=(tmp>>)) if(tmp&) state[state_num].cnt++; //printf("id=%d state=%d cnt=%d\n",state_num,state[state_num].sta,state[state_num].cnt);
}
}//单纯在炮与炮之间不能互相攻击的限制下,得到所有状态 //状态转移过程 - st
memset(dp,,sizeof(dp)); for(int i=;i<=state_num;i++)
{
if(state[i].sta & mp[]) continue;
dp[][i][]=state[i].cnt;
}//初始化dp[1][ state of row1 ][ no state ] for(int i=;i<=state_num;i++)//枚举第2行状态
{
if(state[i].sta & mp[]) continue;
for(int j=;j<=state_num;j++)//枚举第1行状态
{
if( (state[j].sta&mp[]) || (state[i].sta&state[j].sta) ) continue;
dp[][i][j]=max(dp[][i][j],dp[][j][]+state[i].cnt);
}
}//初始化dp[2][ state of row2 ][ state of row1 ] for(int r=;r<=n;r++)
{ for(int i=;i<=state_num;i++)//枚举第r行状态
{ if(state[i].sta & mp[r]) continue; for(int j=;j<=state_num;j++)//枚举第r-1行状态
{ if( (state[j].sta&mp[r-]) || (state[i].sta&state[j].sta) ) continue; for(int k=;k<=state_num;k++)//枚举第r-2行状态
{
if(state[k].sta & mp[r-]) continue;
if( (state[i].sta&state[k].sta) || (state[j].sta&state[k].sta) ) continue; dp[r][i][j]=max(dp[r][i][j],dp[r-][j][k]+state[i].cnt);
} } } }
//状态转移过程 - ed int ans=;
for(int i=;i<=state_num;i++)
{
for(int j=;j<=state_num;j++)
{
ans=max(ans,dp[n][i][j]);
}
}
printf("%d\n",ans);
}

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4539

Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)

Problem Description
  郑厂长不是正厂长
  也不是副厂长
  他根本就不是厂长
  事实上
  他是带兵打仗的团长

  一天,郑厂长带着他的军队来到了一个n*m的平原准备布阵。
  根据以往的战斗经验,每个士兵可以攻击到并且只能攻击到与之曼哈顿距离为2的位置以及士兵本身所在的位置。当然,一个士兵不能站在另外一个士兵所能攻击到的位置,同时因为地形的原因平原上也不是每一个位置都可以安排士兵。
  现在,已知n,m
以及平原阵地的具体地形,请你帮助郑厂长计算该阵地,最多能安排多少个士兵。

 
Input
输入包含多组测试数据;
每组数据的第一行包含2个整数n和m (n <= 100, m <=
10 ),之间用空格隔开;
接下来的n行,每行m个数,表示n*m的矩形阵地,其中1表示该位置可以安排士兵,0表示该地形不允许安排士兵。
 
Output
请为每组数据计算并输出最多能安排的士兵数量,每组数据输出一行。
 
Sample Input
6 6
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
 
Sample Output
2
 
题解:
几乎完全跟上题一样,改一下其中一些判断跳过的条件即可。
 
AC代码:
 #include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 103
#define MAXM 11
using namespace std;
int n,m;
int mp[MAXN]; int state_num;
struct State{
int sta,cnt;
}state[]; int dp[MAXN][][]; int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=,tmp;i<=n;i++)
{
mp[i]=;
for(int j=;j<=m;j++)
{
scanf("%d",&tmp);
tmp=!tmp;
mp[i]|=tmp;
if(j!=m) mp[i]=mp[i]<<;
}
}//二进制记录地图 state_num=;
for(int i=;i<=(<<m)-;i++)
{
if( (i&(i<<))== )
{
state[state_num].sta=i; state[state_num].cnt=;
for(int tmp=i;tmp;tmp=(tmp>>)) if(tmp&) state[state_num].cnt++; //printf("id=%d state=%d cnt=%d\n",state_num,state[state_num].sta,state[state_num].cnt);
state_num++;
}
}//单纯在士兵与士兵之间不能互相攻击的限制下,得到所有状态 //状态转移过程 - st
memset(dp,,sizeof(dp)); for(int i=;i<state_num;i++)
{
if(state[i].sta & mp[]) continue;
dp[][i][]=state[i].cnt;
}//初始化dp[1][ state of row1 ][ no state ] for(int i=;i<state_num;i++)//枚举第2行状态
{
if(state[i].sta & mp[]) continue;
for(int j=;j<state_num;j++)//枚举第1行状态
{
if(state[j].sta & mp[]) continue;
if((state[j].sta<<)&state[i].sta || (state[j].sta>>)&state[i].sta) continue;
dp[][i][j]=max(dp[][i][j],dp[][j][]+state[i].cnt);
}
}//初始化dp[2][ state of row2 ][ state of row1 ] for(int r=;r<=n;r++)
{ for(int i=;i<state_num;i++)//枚举第r行状态
{ if(state[i].sta & mp[r]) continue; for(int j=;j<state_num;j++)//枚举第r-1行状态
{ if(state[j].sta & mp[r-]) continue;
if((state[j].sta<<)&state[i].sta || (state[j].sta>>)&state[i].sta) continue;
for(int k=;k<state_num;k++)//枚举第r-2行状态
{
if(state[k].sta & mp[r-]) continue;
if(state[i].sta & state[k].sta) continue;
if((state[k].sta<<)&state[j].sta || (state[k].sta>>)&state[j].sta) continue; dp[r][i][j]=max(dp[r][i][j],dp[r-][j][k]+state[i].cnt);
} } } }
//状态转移过程 - ed int ans=;
for(int i=;i<state_num;i++)
{
for(int j=;j<state_num;j++)
{
ans=max(ans,dp[n][i][j]);
}
}
printf("%d\n",ans);
}
}

POJ 1185 - 炮兵阵地 & HDU 4539 - 郑厂长系列故事——排兵布阵 - [状压DP]的更多相关文章

  1. HDU 4539 郑厂长系列故事——排兵布阵 —— 状压DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4539 郑厂长系列故事——排兵布阵 Time Limit: 10000/5000 MS (Java/Ot ...

  2. HDU 4539 郑厂长系列故事——排兵布阵 状压dp

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4539 郑厂长系列故事--排兵布阵 Time Limit: 10000/5000 MS (Java/O ...

  3. hdu_4539_郑厂长系列故事——排兵布阵(状压DP|最大团)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4539 题意:中文,不解释 题解:将每一行的状态压缩,然后进行DP,也可以用最大团做.这里我用的DP # ...

  4. HDU 4539郑厂长系列故事――排兵布阵(状压DP)

    HDU 4539  郑厂长系列故事――排兵布阵 基础的状压DP,首先记录先每一行可取的所哟状态(一行里互不冲突的大概160个状态), 直接套了一个4重循环居然没超时我就呵呵了 //#pragma co ...

  5. HDU 4539 郑厂长系列故事——排兵布阵

    http://acm.hdu.edu.cn/showproblem.php?pid=4539 郑厂长系列故事——排兵布阵 Time Limit: 10000/5000 MS (Java/Others) ...

  6. HDU 4539 郑厂长系列故事――排兵布阵(曼哈顿距离)

    这虽然是中文题,然而没看懂,不懂的地方,就是在曼哈顿距离这块,网上搜索了一下,写了个程序,是测试曼哈顿距离的. 曼哈顿距离:两点(x1,y1)(x2,y2)的曼哈顿距离为|x1-x2|+|y1-y2| ...

  7. HDU 4529 郑厂长系列故事——N骑士问题 状压dp

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4529 郑厂长系列故事--N骑士问题 Time Limit: 6000/3000 MS (Java/O ...

  8. hdu4539 郑厂长系列故事——排兵布阵 + POJ1158 炮兵阵地

    题意:                  郑厂长系列故事--排兵布阵 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/32 ...

  9. 郑厂长系列故事——排兵布阵 hdu4539(状态压缩DP)

    郑厂长系列故事——排兵布阵 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)To ...

随机推荐

  1. JAXB XML到java object的转换

    JAXB是Java Architecture for XML Binding的缩写.使用JAXB注解将Java对象转换成XML文件.在这篇教程中,我们将会展示如何使用JAXB来做以下事情: 1. ma ...

  2. [AX2012]关于财务默认维度

    和以前的版本一样,AX2012中很多地方都使用财务维度,比如客户.销售订单.销售订单行等,根据相应的财务维度设置,生成的相应财务分录将带有财务维度,方便后续对财务分录交易的分析.下图是在客户记录上设置 ...

  3. eclipse+pydev 怎么导入已有的python项目

    转自:https://zhidao.baidu.com/question/2117277007790501747.html 已有的python项目导入eclipse的步骤: 1.首先,打开Eclips ...

  4. 基于Python的接口自动化测试框架

    项目背景 公司内部的软件采用B/S架构,目的是进行实验室的数据存储.分析.管理. 大部分是数据的增删改查,但是由于还在开发阶段,所以UI的变化非常快,难以针对UI进行自动化测试,那样会消耗大量的精力与 ...

  5. 【Android】Android中如何取消调转界面后EditText默认获取聚焦问题

    参考资料: https://www.cnblogs.com/dream-cichan/p/aaaa.html http://blog.csdn.net/u013703461/article/detai ...

  6. 【代码审计】iCMS_v7.0.7 admincp.app.php页面存在SQL注入漏洞分析

      0x00 环境准备 iCMS官网:https://www.icmsdev.com 网站源码版本:iCMS-v7.0.7 程序源码下载:https://www.icmsdev.com/downloa ...

  7. PPT高手必须树立的十个理念

    08 2014年08月 [263职场技巧]PPT高手必须树立的十个理念 理念一:文字是用来瞟的,不是读的 我们时不时听到这样的言论:“PPT很简单,就是把Word里的文字复制.粘贴呗.”这其实是对PP ...

  8. error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version

    更新的软件可以解决 TortoiseGit-preview-2.5.7.0-20180127-b2d00f8-64bit.msi和Git-2.16.2-64-bit.exe. 链接地址为: https ...

  9. Python系统编程笔记

    01. 进程与程序 编写完毕的代码,在没有运行的时候,称之为程序 正在运行着的代码,就称为进程 进程是系统分配资源的最小单位. 进程资源包括: 中间变量 代码 计数器 02. 通过os.fork()函 ...

  10. Java 实现文件批量重命名亲测可用(精简版)

    package com.cmge.utils; import java.io.*; import java.util.*; import java.util.Map.Entry; import com ...