luogu2704 炮兵阵地 状态压缩DP
题目大意:一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),在每一格平原地形上最多可以布置一支炮兵部队,能攻击到的区域:沿横向左右各两格,沿纵向上下各两格。保证任何两支炮兵部队之间不能互相攻击时,最多能放置的炮兵数。N<=100,N<=10
动规先要确定方向,我们规定其为从上到下。每一排的最优值与其前两排的各个炮兵的放置位置都有关,所以为了使得DP以后的排时能够找到其对应的前两排的各个炮兵的放置位置所对应的最优值,DP内的参数有:
- 当前的排数i
- 当前排的炮兵状态curS
- 上一排的炮兵状态prevS
定义上两排的炮兵状态为grandS,这样,对于每个满足二进制数内两个1距离超过2的curS,prevS,grandS(因为M是固定的,所以可以在DP前将其算好,叫做RowSs)递归式为:
foreach DP(i, curS, prevS) (curS属于i排平原 且 prevS属于i-1排平原 且 curS∩prevS=空),其值 = max foreach DP(i-1, prevS, grandS)+curS内1的数量 (grandS属于i-2排平原 且 curS∩grandS为空 且 prevS∩grandS为空)
curS内1的数量可以在算完RowSs时一起求出。
一切数组从0开始,DP开始时先特殊处理i=0和1的情况,避免以后在各种特判中搞晕。
DP要用三层滚动数组保存,否则应该会爆空间。
注意:
- 计算RowSs的过程就用二进制的枚举子集,不要想其它方法浪费时间。
- 每到一个i就要将其对应的滚动数组的那一层清空!!!!!!!!!!!!!!!!!!!!
- 注意对N和M下定义,不要搞反了,否则再好的算法也只能得20分。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdarg>
#include <cstdlib>
#include <iostream>
#include <bitset>
using namespace std; const int MAX_N = 110, MAX_M = 10, NINF = 0xcfcfcfcf;
int Map[MAX_N], DP[3][1 << (MAX_M + 1)][1 << (MAX_M+1)], ColSs[1<<(MAX_M+1)], ColNums[1<<(MAX_M+1)];
char CMap[MAX_N][MAX_M];
int N, M, Scnt; #define LOOP0(i, n) for(int i=0; i<(n); i++)
#define LoopFrom(i, m, n) for(int i=(m); i<(n); i++)
#define Update(x, y) x=max(x, y)
#define In(B, A) (((B)&(A))==(B))
#define InterSect(x, y) ((x)&(y))
#define Join(A, x) ((A)|=(1<<(x))) int BCnt(int x)
{
int ans = 0;
while (x)
{
ans += (x & 1);
x >>= 1;
}
return ans;
} int CalColS(int *rowSs, int m)
{
int cnt = 0;
LOOP0(i, 1 << m)
if (!InterSect(i, i << 1) && (!InterSect(i, i << 2)))
{
rowSs[cnt++] = i;
ColNums[i] = BCnt(i);
}
return cnt;
} //S:state
int Proceed()
{
memset(DP, NINF, sizeof(DP));
LOOP0(j, Scnt)
{
int curS = ColSs[j];
if (In(curS, Map[0]))
{
DP[0][curS][0] = ColNums[curS];
}
}
LOOP0(j, Scnt)
{
int curS = ColSs[j];
if (In(curS, Map[1]))
{
LOOP0(k, Scnt)
{
int prevS = ColSs[k];
if (In(prevS, Map[0]) &&
!InterSect(prevS, curS))
{
DP[1][curS][prevS] = DP[0][prevS][0] + ColNums[curS];
}
}
}
}
LoopFrom(i,2,N)
{
memset(DP[i % 3], NINF, sizeof(DP[i % 3]));
LOOP0(j, Scnt)
{
int curS = ColSs[j];
if (In(curS, Map[i]))
{
LOOP0(k, Scnt)
{
int prevS = ColSs[k];
if (In(prevS,Map[i-1])&&
!InterSect(curS, prevS))
{
LOOP0(l, Scnt)
{
int grandS = ColSs[l];
if (In(grandS, Map[i - 2]) &&
!InterSect(curS, grandS) &&
!InterSect(prevS, grandS))
{
Update(DP[i % 3][curS][prevS],
DP[(i - 1) % 3][prevS][grandS] + ColNums[curS]);
}
}
}
}
}
}
}
int ans = 0;
LOOP0(j, Scnt)
{
int curS = ColSs[j];
if (In(curS, Map[N-1]))
{
LOOP0(k, Scnt)
{
int prevS = ColSs[k];
if (In(prevS, Map[N - 2]) && !InterSect(curS, prevS))
Update(ans, DP[(N-1)%3][curS][prevS]);
}
}
}
return ans;
} int main()
{
#ifdef _DEBUG
freopen("c:\\noi\\source\\input.txt", "r", stdin);
#endif
scanf("%d%d", &N, &M);
LOOP0(i, N)
{
scanf("\n%s", i+CMap);
LOOP0(j, M)
if (CMap[i][j] == 'P')
Join(Map[i], j);
}
Scnt = CalColS(ColSs, M);
printf("%d\n", Proceed());
return 0;
}
luogu2704 炮兵阵地 状态压缩DP的更多相关文章
- POJ1185 - 炮兵阵地(状态压缩DP)
题目大意 中文的..直接搬过来... 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平 ...
- POJ1185炮兵阵地(状态压缩 + dp)
题目链接 题意:给出一张n * m的地图,其中 有的地方能放大炮,有的地方不能,大炮与上下左右两个单位范围内会相互攻击,问最多能放几个大炮 能放大炮为1不能放大炮为0,把每一行看做一个状态,要除去同一 ...
- poj 1185 炮兵阵地 状态压缩dp
思路:定义一个三维数组dp[x][i][j]其中x为now和pre两种状态,now表示当前两行最优解,pre表示出了本行外,前两行的最优解.那么状态转移方程为 dp[now][j][k]=max(dp ...
- POJ 3254 炮兵阵地(状态压缩DP)
题意:由方格组成的矩阵,每个方格可以放大炮用P表示,不可以放大炮用H表示,求放最多的大炮,大炮与大炮间不会互相攻击.大炮的攻击范围为两个方格. 分析:这次当前行的状态不仅和上一行有关,还和上上行有关, ...
- POJ - 1185 炮兵阵地 (状态压缩)
题目大意:中文题目就不多说大意了 解题思路: 1.每行最多仅仅有十个位置,且不是山地就是平原,那么就能够用1表示山地,0表示平原,将每一行的状态进行压缩了 2.接着找出每行能放炮兵的状态.先不考虑其它 ...
- [P2704][NOI2001]炮兵阵地 (状态压缩)
最近抄状压的代码…… 然后盯上了这个题目 调试了一个晚上,终于A了 但是是对着宝典打的,我依然不懂状态压缩 那么下一步先把装压放一放,学一下树形DP吧 #include<cstdio> # ...
- POJ1185 炮兵阵地 状态压缩
因为不知道不同的博客怎么转,就把别人的复制过来了,这个题解写的非常好,原地址为: http://hi.baidu.com/wangxustf/item/9138f80ce2292b8903ce1bc7 ...
- luogu P2704 炮兵阵地(经典状态压缩DP)
方格有m*n个格子,一共有2^(m+n)种排列,很显然不能使用暴力法,因而选用动态规划求解. 求解DP问题一般有3步,即定义出一个状态 求出状态转移方程 再用算法实现.多数DP题难youguan点在于 ...
- 浅谈状态压缩DP
浅谈状态压缩DP 本篇随笔简单讲解一下信息学奥林匹克竞赛中的状态压缩动态规划相关知识点.在算法竞赛中,状压\(DP\)是非常常见的动规类型.不仅如此,不仅是状压\(DP\),状压还是很多其他题目的处理 ...
随机推荐
- Redis的持久化——RDB
前面说到redis的三大特性:缓存.分布式内存数据库.持久化,所以今天将为大家介绍redis的两种数据持久化技术RDB和AOF, 先介绍RDB吧. 一.RDB是什么? 1.RDB全称redis dat ...
- ORACLE无法删除当前连接用户
今天在做Oracle数据库是遇到ORACLE无法删除当前连接用户 ,经查找可用如下方法解决 . 在Oracle中删除用户时提示:ORACLE无法删除当前连接用户 可以用以下语句 Sql代码 ...
- 关于maven下载慢的问题
昨天刚接触到maven,尝试在mac上配置maven时发现,下载速度极度缓慢,从网上找了些方法,总算是解决了问题. 修改${maven.home}/conf或者${user.home}/.m2文件夹下 ...
- Gradle讲解
简介: Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建工具.它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置. ...
- [TJOI2019]唱、跳、rap和篮球_生成函数_容斥原理_ntt
[TJOI2019]唱.跳.rap和篮球 这么多人过没人写题解啊 那我就随便说说了嗷 这题第一步挺套路的,就是题目要求不能存在balabala的时候考虑正难则反,要求必须存在的方案数然后用总数减,往往 ...
- [Bzoj3172][Tjoi2013]单词(fail树)
3172: [Tjoi2013]单词 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 4777 Solved: 2345[Submit][Status ...
- Codechef Yet another cute girl
题意大概就是让你求一下[L,R]中的约数个数是素数的数的个数. 其中1<=L<=R<=1e12,R-L<=1e6. 然后我写了两种做法,第一种是可以直接搞出来L-R的约数个数, ...
- File类 文件过滤器
创建过滤器 package cn.zmh.File; import java.io.File; import java.io.FileFilter; // 实现FileFilter类的功能 publi ...
- Ubuntu 16.04安装微信
微信没有出Linux的版本,但是可以通过以下方式解决: 1.使用网页版,除了没有公众号之后,一切都没问题,包括传文件等. 网页登录地址:https://wx.qq.com/ 2.使用第三方版本,只不过 ...
- react+flask+antd
待学习: 1.https://www.cnblogs.com/jlj9520/p/6625535.html 2.http://python.jobbole.com/87112/ 3.