POJ飞翔.数据弱

ZQOJ飞翔 数据强

Description

司令部的将军们打算在N×M的网格地图上部署他们的炮兵部队。一个N×M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:

如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。

Input

多测试数据。

每组测试数据的第一行包含两个由空格分隔的正整数,分别表示N和M;  0 ≤ N ≤ 100;0 ≤ M ≤ 10。

接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。

Output

每组测试数据输出一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。

Sample Input

5 4
PHPP
PPHH
PPPP
PHPP
PHHP

Sample Output

6

题目分析:

经典NOI题,矩阵里的状态压缩问题。因为m<=10,而每列都有状态选或不选,所以想到用2进制,那么状态数是2^10。因为当前行的选择依赖于前两行,而前一行又依赖于前前两行,能想到状态转移方程应该牵扯到当前行、前一行、前前行,类似于递推式dp[i] = dp[i-1] + dp[i-2]的递推过程,而本体每次都是状态间的转移,想到状态转移方程dp[i][j][k] = max(dp[i][k][l]) + sum[j](j和k和l表示当前行状态,前一行状态,前前行状态,sum[j]表示j状态下在i行放了几个大炮)。

用上面的转移方程,空间复杂度和时间复杂度都不允许,因为j,k,l<=2^10,而实际的情况是10列的组合中不冲突的组合只有少数几种,比如PHPP,状态5(101)表示的在第0列和第2列放炮,这个状态内部冲突,我们就可以不考虑,可以预处理把这些状态剔除,然后将不冲突的状态存进一个数组,转移的时候用数组的下标去转移就好。状态转移方程变成:dp[i][j][k] = max(dp[i][k][l]) + one[i][j](j,k,l分别表示第i行,第i-1行,第i-2行的第j个、第k个,第l个状态,状态分别为state[i][j],state[i-1][k],state[i-2][l],one[i][j]表示第i行状态j的1的个数,也就是i状态下放炮数量),最坏复杂度O(N*K^3)(K<62)

AC代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int MAX = ;
const int INF = 0x3f3f3f3f;
const int maxn = ;
///state[i][j]表示第i行第j个合法状态,one表示第i行第j个合法状态中含1的个数
int state[MAX][MAX],one[MAX][MAX],ans;
///stnum[i]表示i行合法的状态数,sum[i]为i状态下1的个数
int stsum[MAX],sum[MAX*];
///dp[i][j][k]表示第i行第j个状态第-1行第k个状态含有的最多1的个数
int dp[MAX][maxn][maxn],map[MAX][MAX],n,m;
void init( )
{
ans=;
memset(dp,,sizeof(dp));
memset(map,,sizeof(map));
memset(one,,sizeof(one));
memset(stsum,,sizeof(stsum));
}
//每个状态里面含有1的数量算出来
void onesum( )
{
for(int i= ; i<=(<<) ; i++)
{
int t=;
for(int j= ; j<= ; ++j)
if(i&(<<j))
t++;
sum[i]=t;
}
}
///判断状态是否符合
bool ok(int x)
{
if(x>&&(x&(x>>)))
return ;
if(x>&&(x&(x>>)))
return ;
return ;
}
///把第x行中合法的状态全部找出来,存到state数组中,tot是本行所有的p点压缩起来的一个状态
void STATE(int x,int tot)
{
for(int i= ; i<(<<m) ; i++)
if(ok(i)&&(i&tot)==i)
///(i&tot) == i表示集合i是集合tot的子集合,意思是i里面的含有的列都是p点
{
stsum[x]++;
int t=stsum[x];
state[x][t]=i;
one[x][t]=sum[i];
}
}
int main( )
{
onesum( );
char tp[MAX];
while(scanf("%d%d",&n,&m)!=EOF)
{
init( );
stsum[]=maxn;
for(int i= ; i<=n ; i++)
{
scanf("%s",tp);
int k=;
for(int j= ; j<m ; j++)
{ //将图变为0,1图
map[i][j] = (tp[j] == 'P' ? : );
k += (map[i][j] ? ( << j) : );
}
STATE(i,k); }
///第一行
for(int i= ; i<=stsum[] ; i++)
for(int j= ; j<=stsum[] ; j++)
dp[][i][j]=one[][i];
for(int i= ; i<=n ; i++)
for(int j= ; j<=stsum[i] ; j++)///枚举第i行的状态
for(int k= ; k<=stsum[i-] ; k++)///枚举第i-1行的状态
{/// 判断两个状态是否有冲突
if(state[i][j]&state[i-][k])
continue;
int t=;
for(int s= ; s<=stsum[i-] ; s++)///枚举第i-2行的状态
{
if(state[i][j]&state[i-][s])/// 判断三个状态是否有冲突
continue;
if(state[i-][k]&state[i-][s])
continue;
t=max(dp[i-][k][s],t);
}
dp[i][j][k]=t+one[i][j];
}
for(int j= ; j<=stsum[n] ; j++)
for(int k= ; k<=stsum[n-] ; k++)
ans=max(ans,dp[n][j][k]);
printf("%d\n",ans);
}
return ;
}

POJ1185炮兵阵地(状态压缩DP)的更多相关文章

  1. POJ1185 - 炮兵阵地(状态压缩DP)

    题目大意 中文的..直接搬过来... 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平 ...

  2. POJ1185炮兵阵地(状态压缩 + dp)

    题目链接 题意:给出一张n * m的地图,其中 有的地方能放大炮,有的地方不能,大炮与上下左右两个单位范围内会相互攻击,问最多能放几个大炮 能放大炮为1不能放大炮为0,把每一行看做一个状态,要除去同一 ...

  3. POJ1185 炮兵阵地 状态压缩

    因为不知道不同的博客怎么转,就把别人的复制过来了,这个题解写的非常好,原地址为: http://hi.baidu.com/wangxustf/item/9138f80ce2292b8903ce1bc7 ...

  4. luogu2704 炮兵阵地 状态压缩DP

    题目大意:一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),在每一格平原地形上最多可以布置一支炮兵部队,能攻击到的区域:沿横向左右各两格,沿纵向上 ...

  5. poj 1185 炮兵阵地 状态压缩dp

    思路:定义一个三维数组dp[x][i][j]其中x为now和pre两种状态,now表示当前两行最优解,pre表示出了本行外,前两行的最优解.那么状态转移方程为 dp[now][j][k]=max(dp ...

  6. POJ 3254 炮兵阵地(状态压缩DP)

    题意:由方格组成的矩阵,每个方格可以放大炮用P表示,不可以放大炮用H表示,求放最多的大炮,大炮与大炮间不会互相攻击.大炮的攻击范围为两个方格. 分析:这次当前行的状态不仅和上一行有关,还和上上行有关, ...

  7. POJ - 1185 炮兵阵地 (状态压缩)

    题目大意:中文题目就不多说大意了 解题思路: 1.每行最多仅仅有十个位置,且不是山地就是平原,那么就能够用1表示山地,0表示平原,将每一行的状态进行压缩了 2.接着找出每行能放炮兵的状态.先不考虑其它 ...

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

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

  9. [P2704][NOI2001]炮兵阵地 (状态压缩)

    最近抄状压的代码…… 然后盯上了这个题目 调试了一个晚上,终于A了 但是是对着宝典打的,我依然不懂状态压缩 那么下一步先把装压放一放,学一下树形DP吧 #include<cstdio> # ...

  10. poj1185 炮兵阵地 状压dp

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

随机推荐

  1. 【Java基础专题】编码与乱码(05)---GBK与UTF-8之间的转换

    原文出自:http://www.blogjava.net/pengpenglin/archive/2010/02/22/313669.html 在很多论坛.网上经常有网友问" 为什么我使用 ...

  2. 使用Get进行Http通信

    --------------siwuxie095 有道翻译官网:http://fanyi.youdao.com/ 找到官网页面下方的 有道翻译API,选择 调用数据接口,申请一个 key (申请内容可 ...

  3. SqlServer中把结果集放到到临时表的方法(转)

    一. SELECT INTO   1. 使用select into会自动生成临时表,不需要事先创建   select * into #temp from sysobjects   01. 把存储过程结 ...

  4. [转]JQuery 如何选择带有多个class的元素

    比如下面代码需要选择同时带有这几个class的元素,怎么写? 1 <div class="modal fade in"></div> A: 1. 依次过滤 ...

  5. Linux minicom命令

    一.简介 minicom是Linux下的超级终端,与Windows下的超级终端功能相似,可以通过串口控制外部的硬件设备,可以用于管理和控制嵌入式设备 二.安装 1)yum安装 yum install ...

  6. ARC059F

    传送门 分析 见ptx大爷博客 代码 #include<iostream> #include<cstdio> #include<cstring> #include& ...

  7. Luogu 3402 可持久化并查集

    点开这题纯属无聊……不过既然写掉了,那就丢一个模板好了 不得不说,可持久化并查集实现真的很暴力,就是把并查集的数组弄一个主席树可持久化. 有一点要注意的是不能写路径压缩,这样跳版本的时候会错,所以弄一 ...

  8. ubuntu基础知识与技巧

    root用户与超级用户的切换 (1)  sudo -i (2)  sudo su (3)  su root 安装升级 查看软件xxx安装内容 dpkg -L xxx 查找软件库中的软件 apt-cac ...

  9. 国外物联网平台(2):微软Azure IoT

    国外物联网平台(2)——微软Azure IoT 马智 平台定位 连接设备.其它 M2M 资产和人员,以便在业务和操作中更好地利用数据. 连接 IoT 设备 将所有设备连接到云,从这些设备接收大规模数据 ...

  10. android studio 程序员有福了—从layout自动生成viewholder类

    狂点这里下载 超级牛逼的插件啊,比那些使用SparseArray的强太多了! 在android studio 1.0上测试,没有问题. 不说了直接说功能 Android Toolbox Plugin ...