luogu P2704 炮兵阵地(经典状态压缩DP)
方格有m*n个格子,一共有2^(m+n)种排列,很显然不能使用暴力法,因而选用动态规划求解.
求解DP问题一般有3步,即定义出一个状态 求出状态转移方程 再用算法实现.多数DP题难youguan点在于第2步,而在状态压缩DP中,定义状态也是很关键的一个步骤.有关位运算的基础知识,按位与,按位或,异或等可自行查阅资料,这里仅作简单说明.
<<n == 2的n次方
>>n == /2的n次方
(n>>k) & // 取出整数n在二进制下的第k位
n & ((<<k)-) // 取出整数n在二进制下的后k位
(i>>j) & k // i右移j位后和k与运算
很容易想到用二进制数来表示方格,1表示放炮兵,0表示不放.在同一行中,只要没有出现两个炮兵紧邻或者两个炮兵只间隔1个位置的情况,均是合法的状态.故在二进制表示的行01串中删除字串含有"11","101"的原串即可,预处理出合法的01串并存于legal中.
vector<int> legal;
void init() { // 找到合法的摆放总数
for(int i = ; i < (<<m); i++) { // 1<<m == pow(2,m),遍历所有情况
int c1 = , c2 = ; // 3 -> (11) , 5 -> (101)
bool sub = ;
for(int j = ; j < m - ; j++) {
if(((i >> j) & c1) == c1) {
sub = ;
}
}
for(int j = ; j < m - ; j++) {
if(((i >> j) & c2) == c2) {
sub = ;
}
}
if(sub) legal.push_back(i);
}
}
并用count函数计算每行中的1(炮兵数目):
int count(int x) {
int cnt = ;
for(int i = ; i < m; i++) {
if(((x>>i)&) == ) {
cnt++;
}
}
return cnt;
}
接下来设计DP状态和状态转移
每一行的状态受该行前两行摆放状态的影响,因此选择dp[i][j][k]表示可行方案数.dp[i][j][k]表示第i行压缩后状态为j,第i-1行压缩后状态为k的情况下前i行最多放多少个炮兵.同时由于dp[102][1050][1050]会MLE,只有80分不过也知足了, 需要将dp改为滚动数组,将第一维每处均%3即可,只记录前两次的状态
读入地图时把每行压缩成一个二进制数,为了便于后续查找可行状态,读入时H对应1,P对应0. 后续遍历了legal中的合法状态时,若与该行的01表示与运算值不为0,即与地图存在冲突.
状态转移方程为dp[本行][前一行][再前一行] = max{dp[前一行][再前一行][再前一行的前一行] + count(本行) , dp[本行][前一行][再前一行]}
完整的代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + ; int n, m;
string s;
int mp[];
vector<int> legal; // 储存所有的合法01串
int dp[][][]; void init() { // 找到合法的摆放总数
for(int i = ; i < (<<m); i++) { // 1<<m == pow(2,m)
int c1 = , c2 = ; // 3 -> (0011) , 5 -> (0101)
bool sub = ;
for(int j = ; j < m - ; j++) {
if(((i >> j) & c1) == c1) {
sub = ;
}
}
for(int j = ; j < m - ; j++) {
if(((i >> j) & c2) == c2) {
sub = ;
}
}
if(sub) legal.push_back(i);
}
} int count(int x) {
int cnt = ;
for(int i = ; i < m; i++) {
if(((x>>i)&) == ) {
cnt++;
}
}
return cnt;
} int main() {
cin>>n>>m;
init();
// cout<<legal.size()<<endl;
for(int i = ; i <= n + ; i++) { // i初值2 避免越界(需考虑到前两行)
cin>>s;
for(int j = ; j < m; j++)
if(s[j] == 'H') mp[i] |= (<<j);
}
for(int i = ; i <= n + ; i++) {
for(auto step : legal) {
if((step & mp[i]) != ) continue;
for(auto bst : legal) {
if((step & bst) != ) continue;
if((bst & mp[i-]) != ) continue;
for(auto bbst : legal) {
if((step & bbst) != ) continue;
if((bbst & mp[i-]) != ) continue;
if((bbst & bst) != ) continue;
dp[i%][step][bst] = max(dp[(i-)%][bst][bbst] + count(step), dp[i%][step][bst]);
}
}
}
}
int res = ;
for(auto step : legal)
for(auto bst : legal)
res = max(res, dp[(n+)%][step][bst]);
cout<<res<<endl;
}
luogu P2704 炮兵阵地(经典状态压缩DP)的更多相关文章
- poj 1185 炮兵阵地 [经典状态压缩DP]
题意:略. 思路:由于每个大炮射程为2,所以如果对每一行状态压缩的话,能对它造成影响的就是上面的两行. 这里用dp[row][state1][state2]表示第row行状态为state2,第row- ...
- 洛谷 P2704 [NOI2001]炮兵阵地 (状态压缩DP+优化)
题目描述 司令部的将军们打算在NM的网格地图上部署他们的炮兵部队.一个NM的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P" ...
- POJ1185炮兵阵地(状态压缩DP)
POJ飞翔.数据弱 ZQOJ飞翔 数据强 Description 司令部的将军们打算在N×M的网格地图上部署他们的炮兵部队.一个N×M的地图由N行M列组成,地图的每一格可能是山地(用"H&q ...
- POJ 1185 炮兵阵地 (状态压缩DP)
题目链接 Description 司令部的将军们打算在NM的网格地图上部署他们的炮兵部队.一个NM的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用& ...
- POJ 1185 炮兵阵地(状态压缩DP)
题解:nState为状态数,state数组为可能的状态 代码: #include <map> #include <set> #include <list> #inc ...
- poj 1185 炮兵阵地(三维状态压缩dP)
题目:http://poj.org/problem?id=1185 思路: d[i][j][k]表示第i行的状态为第k个状态,第i-1行的状态为第j个状态的时候 的炮的数量. 1表示放大炮, 地形状态 ...
- POJ 2411 Mondriaan's Dream [经典状态压缩dp]
题意:略. 思路:这一题开始做的时候完全没有思路,便去看了别人的题解. 首先,对于这个题目解法想有一个初步的了解,请看这里:http://www.2cto.com/kf/201208/146894.h ...
- poj -1185 炮兵阵地 (经典状压dp)
http://poj.org/problem?id=1185 参考博客:http://poj.org/problem?id=1185 大神博客已经讲的很清楚了,注意存状态的时候是从1开始的,所以初始化 ...
- 【Luogu】P2704炮兵阵地(状压DP)
题目链接 话说还真没见过能影响两行的状压.想了半天想出来f数组再多一维就能表示,但是没想到怎么才能不爆空间…… 也是从这道题里学到的一个妙招. 可以把合法状态存到一个数组里,然后用数组下标来映射状态. ...
随机推荐
- MySQL多表创建关联及操作
外键 现在有两张表“分类表”和“商品表”,为了表明商品属于哪个 类别,通常情况下,我们将在商品上添加一列,用来存放分类的cid信息,此列成为外键. 此时,分类表 category 称作主表,cid 成 ...
- aarch64环境下,搭建并配置服务器tomcat:
aarch64环境下,搭建并配置服务器tomcat: 环境说明及下载相关文件: 1. ARM环境:aarch64开发板 2.JDK安装包: jdk-8u231-linux-arm64-vfp-hflt ...
- 【PAT甲级】1075 PAT Judge (25 分)
题意: 输入三个正整数N,K,M(N<=10000,K<=5,M<=100000),接着输入一行K个正整数表示该题满分,接着输入M行数据,每行包括学生的ID(五位整数1~N),题号和 ...
- 基于SILVACO ATLAS的a-IGZO薄膜晶体管二维器件仿真(02)
Silvaco的破解用了好久好久,而且之后拷了上次例子的代码,Tonyplot的输出存在报错,还是四连. 当然这个点一下还是会出图的.但是,源代码稍微改了下结构,又有报错,而且程序直接终止. go a ...
- 用python计算一条射线到两个平面的交点
前两天,一个朋友找我(半个程序猿)用python帮他写数学模型,当时的我直接是懵逼的,当听到三维啥的时候,整个人就好了,最终在周末花了3个小时把逻辑理了一遍,给小伙伴一个满意的答复了,话不多说,我来整 ...
- 数码管显示“0~F”的共阳共阴数码管编码表
嵌入式设备中数码管显示“0~F”的方式是:定义了一个数组,里面含有16个元素,分别代表0~F,这样可以方便以后的调用.共阳极数码管编码表:unsigned char table[]={0xc0,0xf ...
- hackme.inndy.tw - pyyy
0x01 反编译 1.第一次尝试的时候我直接在线反编译,部分结果如下. for (i, f) in enumerate(F): n = pow(f, m, g) this_is = 'Y-Combin ...
- SQLite - C/C++接口 API(二)
1.打开数据库 SQLITE_API int sqlite3_open16( const void *filename, /* Database filename (UTF-16) */ sqlite ...
- 基于G6画个xmind出来
公司产品因为业务发展,出现了一个新的需求:需要去实现知识库的层级知识展示,展示效果通过树图来实现,具体的展示形式可见下图: 其中有几个需要注意点: 节点上的详情icon可以点击,点击展开关闭详情 节点 ...
- Codeforces 1045F Shady Lady 凸包+数学
题目链接:https://codeforc.es/contest/1045/problem/F 题意:先给出一个系数不确定的二元多项式,Borna可以给这个多项式的每一项填上正的系数,Ani能从这个多 ...