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

炮兵阵地
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 29176   Accepted: 11303

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

   很有趣的题目,由于炮兵攻击范围达到了两行所以我们枚举当前行状态时肯定需要前两行的状态,有一个显然的方程为 f[i][j][k]=MAX{  f[i-1][v][j] | if(i,j,k对应的三行的状态可以共存 }
每行状态最多210,这样算的话肯定会T,但是仔细想想会发现合法的状态最多只有60多个,因为只要存在相邻的1就不合法,所以可以筛去很多的状态,将这些状态离散化,a[i]为第i个合法状态,t[i]为第i个状态中‘1’的个数。接着我们就能用f[i][j][k]表示第i行为第k个合法状态,第i-1行为第j个合法状态时最大炮兵个数,复杂度大大降低。注意每次都要判断三个状态能否放在对应的三行上以及是否可以共存,这些关系的判断使用打表法存下,因为要进行多次判断,第一次直接计算结果T了,打表之后250ms A了,虽然不是很快- -

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long
int e[][];
int f[][][];
int N,M,tot,all;
int a[],t[];
int g[][];
int _g[][];
int sol(int x)
{
int r=;
for(int j=;j<M;++j)
{
if(x&(<<j)) {
r++;
for(int i=-;i<=;++i)
{
if(i==||j+i<||j+i>=M) continue;
if(x&(<<(j+i))) return -;
}
}
}
return r;
}
void init()
{
for(int i=;i<all;++i)
{
int x=sol(i);
if(x!=-){
a[tot]=i;
t[tot++]=x;
}
}
}
bool ok(int _a,int x)
{
int A=a[_a];
for(int i=;i<M;++i)
if((A&(<<i))&&e[x][M-i]) return ;
return ;
}
bool match(int _a,int _b)
{
int A=a[_a],B=a[_b];
for(int i=;i<M;++i)
if((A&(<<i))&&(B&(<<i))) return ;
return ;
}
int main()
{
int i,j,k=;
while(scanf("%d%d",&N,&M)==){tot=;
all=(<<M);memset(e,,sizeof(e));
memset(f,,sizeof(f));
memset(g,-,sizeof(g));
memset(_g,-,sizeof(_g));
for(i=;i<=N+;++i)
for(j=;j<=M;++j){
char c;
scanf(" %c",&c);
e[i][j]=c=='P'?:;
}
init();
for(i=;i<tot;++i)
for(j=;j<=N+;++j)
_g[i][j]=ok(i,j);
for(i=;i<tot;++i)
for(j=;j<tot;j++)
g[i][j]=match(i,j);
for(i=;i<=N+;++i)
{
for(int t1=;t1<tot;++t1)
{
if(!_g[t1][i-]) continue;
for(int t2=;t2<tot;++t2)
{
if(!_g[t2][i-]||!g[t1][t2]) continue;
for(int t3=;t3<tot;++t3)
{
if(!_g[t3][i]||!g[t2][t3]||!g[t1][t3]) continue;
if(f[i][t2][t3]<f[i-][t1][t2]+t[t3])f[i][t2][t3]=f[i-][t1][t2]+t[t3];
}
}
}
}
int ans=;
for(int t1=;t1<tot;++t1)
for(int t2=;t2<tot;++t2)
if(ans<f[N+][t1][t2])ans=f[N+][t1][t2];
printf("%d\n",ans);
}
return ;
}

poj 1185 状压dp+优化的更多相关文章

  1. poj 1185(状压dp)

    题目链接:http://poj.org/problem?id=1185 思路:状态压缩经典题目,dp[i][j][k]表示第i行状态为j,(i-1)行状态为k时最多可以放置的士兵个数,于是我们可以得到 ...

  2. 炮兵阵地(POJ 1185状压dp)

    题意:n*m地图'H'能放'p'不能放,布兵的方格上下左右不能布兵,给你地图求最大布兵数 分析:关系到前两行,所以dp[i][j][k]第i行状态为j,i-1行状态为k时的最大布兵数, 先求出所有可行 ...

  3. POJ1038 Bugs Integrated, Inc 状压DP+优化

    (1) 最简单的4^10*N的枚举(理论上20%) (2) 优化优化200^3*N的枚举(理论上至少50%) (3) Dfs优化状压dp O(我不知道,反正过不了,需要再优化)(理论上80%) (4) ...

  4. POJ 3254 (状压DP) Corn Fields

    基础的状压DP,因为是将状态压缩到一个整数中,所以会涉及到很多比较巧妙的位运算. 我们可以先把输入中每行的01压缩成一个整数. 判断一个状态是否有相邻1: 如果 x & (x << ...

  5. poj 1170状压dp

    题目链接:https://vjudge.net/problem/POJ-1170 题意:输入n,表示有那种物品,接下来n行,每行a,b,c三个变量,a表示物品种类,b是物品数量,c代表物品的单价.接下 ...

  6. hdu 1185 状压dp 好题 (当前状态与上两行有关系)

    /* 状压dp 刚开始&写成&&看了好长时间T0T. 状态转移方程 dp[i][k][j]=Max(dp[i][k][j],dp[i-1][l][k]+num[i][j]);( ...

  7. POJ 2411 状压DP经典

    Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 16771   Accepted: 968 ...

  8. POJ 3254 状压DP

    题目大意: 一个农民有一片n行m列 的农场   n和m 范围[1,12]  对于每一块土地 ,1代表可以种地,0代表不能种. 因为农夫要种草喂牛,牛吃草不能挨着,所以农夫种菜的每一块都不能有公共边. ...

  9. poj 3254 状压dp入门题

    1.poj 3254  Corn Fields    状态压缩dp入门题 2.总结:二进制实在巧妙,以前从来没想过可以这样用. 题意:n行m列,1表示肥沃,0表示贫瘠,把牛放在肥沃处,要求所有牛不能相 ...

随机推荐

  1. Python是如何进行类型转换的?

    函数                      描述int(x [,base ])         将x转换为一个整数long(x [,base ])        将x转换为一个长整数float(x ...

  2. 学习pyhton需要做哪些准备工作

    1:知道python个版本是有差异的 2:既然有差异,那么如何在不同项目不同版本的开发环境; ----------------------------------------------------- ...

  3. docker快速构建oracle数据库

    1.查看可用镜像docker search oracle2.拉去想要的镜像docker pull wnameless/oracle-xe-11g3.基于wnameless/oracle-xe-11g创 ...

  4. 剑指offer 面试43题

    面试43题: 题目:1~n整数中1出现的次数 题:输入一个整数n,求1~n这n个整数的十进制表示中1出现的次数.例如,输入12,1~12这些整数中包含1的数字有1,10,11,12一共出现了5次. 解 ...

  5. admin 模块功能

    class CustomModelAdmin(admin.ModelAdmin): def has_module_permission(self, request): 是否会显示model def h ...

  6. 谷歌机器学习速成课程---降低损失 (Reducing Loss):随机梯度下降法

    在梯度下降法中,批量指的是用于在单次迭代中计算梯度的样本总数.到目前为止,我们一直假定批量是指整个数据集.就 Google 的规模而言,数据集通常包含数十亿甚至数千亿个样本.此外,Google 数据集 ...

  7. 吐槽 坑爹的MySQL安装路径选择

    一般再windows下面安装MySQL我们都会选择msi安装模式,然而安装最新版的MySQL(mysql-installer-community-5.7.11.0.msi 下载地址)发现MySQL默认 ...

  8. INDEL的重新比对和碱基质量分数的重新校准

    1.为什么要做这两步(why): indel的重新比对:这是由于比对软件的自身限制,其可能将包括indel的read解释为snp的read,这就导致calling的错误和后面的碱基质量分数的重新校准. ...

  9. 语义web基础知识学习

    最近找了一本书,<语义web技术基础>----Pascal Hitzler等编著的.因为最近在看关于自然语言处理的一些东西,就顺带翻了一下,做一点学习笔记,方便以后查看. 本书的作者 Pa ...

  10. 算法总结之 删除链表的中间节点和a/b处的节点(链表中间节点的重要思想)

    给定链表的表头节点head,实现删除链表的中间节点的函数 推展: 给定链表的头节点,整数a 和 整数 b,实现删除a/b处节点的函数 先来分析原问题, 长度1  直接返回 长度2 将头节点删除 长度3 ...