题目描述

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

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

输入输出格式

输入格式:

第一行包含两个由空格分割开的正整数,分别表示N和M;

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

输出格式:

仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。

输入输出样例

输入样例#1:

5 4

PHPP

PPHH

PPPP

PHPP

PHHP

输出样例#1:

6

题意:



思路:



状压DP

因为每一行要对下面两行有影响,所以我们定义DP状态就要维护前两行状态的信息,即

dp[i][j][k] 代表 到第i行,当前行是第j个状态,上一行是第k个状态,最大的部署数量。

我们知道如果一行有m个方格,那么最多有 2^m 个状态, 而m最大是10,

那么如果我们不进行优化,dp数组要开到 dp[100][1024][1024] 我们应该知道,这个数组太大了,我们是开不到这么大的数组的。

那么我们应该如何优化呢?我们从题目中的一个信息来入手,每一行一个炮台对左右两个位置都有影响,那么减去一行中,两个1的距离最少为3,这样一来合法的状态数量就少之又少。

通过程序我们可以得知,合法的状态数不大于110,那么我们可以枚举 第i合法状态来DP,用一个数组INDEX来存具体的状态信息, 即INDEX[i] 为第i个合法状态的具体状态信息。

这样我们就优化了时空。

状态转移方程为:

dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][w]+num[INDEX[j]]);

细节见代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define rt return
#define dll(x) scanf("%I64d",&x)
#define xll(x) printf("%I64d\n",x)
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll powmod(ll a,ll b,ll MOD){ll ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
inline void getInt(int* p);
const int maxn=1000010;
const int inf=0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
int n;
int m;
int a[500];
bool can[(1<<11)];
bool can2[300][123];
int dp[120][123][123];
int ans=0;
int INDEX[maxn];
int cnt=0;
int num[(1<<11)];
int main()
{
// freopen("D:\\common_text\\code_stream\\in.txt","r",stdin);
//freopen("D:\\common_text\code_stream\\out.txt","w",stdout);
gbtb;
cin>>n>>m;
char c;
repd(i,1,n)
{
repd(j,1,m)
{
cin>>c;
if(c=='P')
{
a[i]=(a[i]<<1)+1;
}else
{
a[i]=(a[i]<<1);
}
}
}
int maxstate=(1<<m)-1;// 最大状态数
for(int i=0;i<=maxstate;i++)
{
if(((i<<1)&i)==0&&((i<<2)&i)==0&&((i>>2)&i)==0&&((i>>1)&i)==0)// 同一行内两个1之间至少要有两个空格
{
INDEX[++cnt]=i;
can[cnt]=1;
int j=i;
while(j)
{
if(j&1)
{
num[i]++;
}
j>>=1;
} }
}
// can2[i][j] 代表在第i行中,第j个状态是合法的状态。
for(int i=1;i<=cnt;i++)
{
int x=INDEX[i];
if(((x&a[1])==x))
{
can2[1][i]=1;
dp[1][i][0]=num[x];
}
}
for(int i=1;i<=cnt;++i)
{
if(((INDEX[i]&a[2])==INDEX[i]))
{
can2[2][i]=1;
for(int j=1;j<=cnt;++j)
{
if(can2[1][j])
{
if((INDEX[i]&INDEX[j])==0)
{
dp[2][i][j]=max(dp[2][i][j],dp[1][j][0]+num[INDEX[i]]);
}
}
}
}
}
for(int i=3;i<=n;++i)
{
for(int j=1;j<=cnt;j++)
{
if(((INDEX[j]&a[i])==INDEX[j]))
{
can2[i][j]=1;
for(int k=1;k<=cnt;k++)
{
if(can2[i-1][k])
{
if((INDEX[k]&INDEX[j])==0)
{
for(int w=1;w<=cnt;++w)
{
if(can2[i-2][w])
{
if((INDEX[w]&INDEX[j])==0&&(INDEX[w]&INDEX[k])==0)// 和上面两行均没重合的1
dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][w]+num[INDEX[j]]);
}
}
}
}
}
}
}
}
for(int i=1;i<=cnt;++i)
{
for(int j=1;j<=cnt;j++)
{
ans=max(ans,dp[n][i][j]);
}
}
cout<<ans<<endl;
return 0;
} inline void getInt(int* p) {
char ch;
do {
ch = getchar();
} while (ch == ' ' || ch == '\n');
if (ch == '-') {
*p = -(getchar() - '0');
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 - ch + '0';
}
}
else {
*p = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 + ch - '0';
}
}
}

洛谷 P2704 [NOI2001]炮兵阵地 (状态压缩DP+优化)的更多相关文章

  1. 洛谷P2704 [NOI2001]炮兵阵地 [状压DP]

    题目传送门 炮兵阵地 题目描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图 ...

  2. C++ 洛谷 P2704 [NOI2001]炮兵阵地

    P2704 [NOI2001]炮兵阵地 没学状压DP的看一下 此题意思很简单,如下图,就是十字架上的不能有两个点放炮兵. 在做此题前,先做一下玉米田 玉米田题解 分析: 而m即一行的个数小于等于10, ...

  3. [洛谷P2704] [NOI2001]炮兵阵地

    洛谷题目链接:[NOI2001]炮兵阵地 题目描述 司令部的将军们打算在NM的网格地图上部署他们的炮兵部队.一个NM的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示), ...

  4. 【题解】洛谷P2704 [NOI2001] 炮兵阵地(状压DP)

    洛谷P2704:https://www.luogu.org/problemnew/show/P2704 思路 这道题一开始以为是什么基于状压的高端算法 没想到只是一道加了一行状态判断的状压DP而已 与 ...

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

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

  6. 洛谷 P2704 [NOI2001]炮兵阵地

    题意简述 给定一张地图,有山地H,平原P,平原可放置炮兵, 炮兵可以攻击沿横向左右各两格,沿纵向上下各两格的区域 求最多放几个炮兵,使他们两两攻击不到 题解思路 枚举第i层,第i - 1层,第i - ...

  7. 洛谷P2704 [NOI2001]炮兵阵地题解

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

  8. P2704 [NOI2001]炮兵阵地 (状压DP)

    题目: P2704 [NOI2001]炮兵阵地 解析: 和互不侵犯一样 就是多了一格 用\(f[i][j][k]\)表示第i行,上一行状态为\(j\),上上行状态为\(k\)的最多的可以放的炮兵 发现 ...

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

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

随机推荐

  1. 在linux下搭建go环境

    这几天小Jerry开始接触Go语言了,因为小Jerry学个东西必须要从最基础的开始弄懂,不然~她理解不了<hahaha> 所以,今天就来讲最基础,却也很容易让小Jerry这样的菜鸟感到困扰 ...

  2. Loading class `com.mysql.jdbc.Driver'. This is deprecated警告处理,jdbc更新处

    1.报错信息是这样的; 处理:提示信息表明数据库驱动com.mysql.jdbc.Driver'已经被弃用了.应当使用新的驱动com.mysql.cj.jdbc.Driver' 所以,按照提示更改jd ...

  3. iOS自动化--Spaceship使用实践

    Spaceship ### 脚本操作 证书,app,provision等一些列apple develop后台操作,快速高效. github地址 spaceship开发文档 文档有列出常用的api调用d ...

  4. jQuery file upload cropper的流程

    https://tkvw.github.io/jQuery-File-Upload/basic-plus-editor.html 最开始初始化jquery.ui.widget.js中的factory( ...

  5. webpack配置之webpack.config.js文件配置

    webpack配置之webpack.config.js文件配置 webpack.config.js webpack resolve  1.总是手动的输入webpack的输入输出文件路径,是一件非常繁琐 ...

  6. eigen 四元数进行坐标旋转

    (<视觉SLAM十四讲>第三讲习题7)设有小萝卜一号和二号在世界坐标系中.一号位姿q1 = [0.35, 0.2, 0.3, 0.1],t1=[0.3, 0.1, 0.1].二号位姿q2= ...

  7. RotateZoom.cpp——Inter

    // RotateZoom.cpp : Defines the entry point for the console application. // #include "stdafx.h& ...

  8. .Net Core-3.0-新闻:宣告推出.NET Core 3.0 Preview 7

    ylbtech-.Net Core-3.0-新闻:宣告推出.NET Core 3.0 Preview 7  1.返回顶部 1. 今天,我们宣布推出.NET Core 3.0 Preview 7.我们已 ...

  9. 阶段3 1.Mybatis_07.Mybatis的连接池及事务_6 mybatis中的事务原理和自动提交设置

    在实际的开发中,建议使用连接池的形式. JNDI的资料 H:\BaiDu\黑马传智JavaEE57期 2019最新基础+就业+在职加薪\讲义+笔记+资料\主流框架\31.会员版(2.0)-就业课(2. ...

  10. 使用python脚本部署mariadb主从架构

    环境准备 一个脚本自动部署master服务 另一个部署slave服务 关闭主从节点的防火墙 以及事先设置好root远程登陆的权限. grant all on *.* to root@'%'  iden ...