题目大意:一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),在每一格平原地形上最多可以布置一支炮兵部队,能攻击到的区域:沿横向左右各两格,沿纵向上下各两格。保证任何两支炮兵部队之间不能互相攻击时,最多能放置的炮兵数。N<=100,N<=10

动规先要确定方向,我们规定其为从上到下。每一排的最优值与其前两排的各个炮兵的放置位置都有关,所以为了使得DP以后的排时能够找到其对应的前两排的各个炮兵的放置位置所对应的最优值,DP内的参数有:

  1. 当前的排数i
  2. 当前排的炮兵状态curS
  3. 上一排的炮兵状态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的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

  7. POJ1185 炮兵阵地 状态压缩

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

  8. luogu P2704 炮兵阵地(经典状态压缩DP)

    方格有m*n个格子,一共有2^(m+n)种排列,很显然不能使用暴力法,因而选用动态规划求解. 求解DP问题一般有3步,即定义出一个状态 求出状态转移方程 再用算法实现.多数DP题难youguan点在于 ...

  9. 浅谈状态压缩DP

    浅谈状态压缩DP 本篇随笔简单讲解一下信息学奥林匹克竞赛中的状态压缩动态规划相关知识点.在算法竞赛中,状压\(DP\)是非常常见的动规类型.不仅如此,不仅是状压\(DP\),状压还是很多其他题目的处理 ...

随机推荐

  1. RSA工作原理

    摘自:http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html 一.基础数论 1.互质关系 如果两个正整数,除了1以外,没有 ...

  2. K-lord #2

    题目描述 还记得,高中数学联赛,2005,那道毒瘤题. 如果自然数的各位数字之和等于7,那么称为“吉祥数”.将所有“吉祥数”从小到大排成一列 $a_{1}$,$a_{2}$,$a_{3}$ ... , ...

  3. P3146 [USACO16OPEN]248 (区间DP)

    题目描述  给定一个1*n的地图,在里面玩2048,每次可以合并相邻两个(数值范围1-40),问最大能合出多少.注意合并后的数值并非加倍而是+1,例如2与2合并后的数值为3. 这道题的思路: 状态: ...

  4. HashTable的构造函数有哪些

    HashTable:在并发的环境下,使用synchronized将整张表锁住: HashTable构造函数有: public Hashtable(int initialCapacity, float ...

  5. mongo 操作符

    1 $unset The $unset operator deletes a particular field. https://docs.mongodb.com/manual/reference/o ...

  6. Codevs 2956 排队问题

    2956 排队问题 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 黄金 Gold 题目描述 Description 有N个学生去食堂,可教官规定:必须2人或3人组成一组,求有多少种不 ...

  7. 【Codeforces Round #503 (Div. 2)】

    A:https://www.cnblogs.com/myx12345/p/9843198.html B:https://www.cnblogs.com/myx12345/p/9843245.html ...

  8. 小窥React360——用React创建360全景VR体验

    前言    混迹VR届的发烧友兼开发者们一定不要错过这款FaceBook推出的跨端VR开发框架——React360,称为360全景体验框架更为准确,因为其前身是FaceBook和Oculus2017年 ...

  9. Windows Phone 8.1 开发实例 网络编程 天气预报

    首先感谢林政老师的博客,给了我很大的指导. 准备工作 我的开发环境: - Visual Studio 2013(With Update 4) - Windows Phone 8.1 - Windows ...

  10. gorm 结构体 预加载

    结构体构建 type PlansApproval struct {     ID uint     Plans_Id int //plans编号     UpdateUser int //更新者    ...