洛谷P2704 炮兵阵地

P2704 炮兵阵地

题目描述

司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由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

首先预处理出每一行所有符合条件的状态s,0表示无炮,1表示有炮,并预处理出每种状态的炮数num[i]
处理出每一行的高低情况,1表示不能放, 0表示能放
定义状态F[i][j][k]表示前i行,第i行为k,第i - 1行为j的最大炮数,转移:
F[i][j][k] = max(F[i - 1][l][j] + num[k])
预处理出F[1][1][k] = num[k]
转移和预处理时注意判断状态的合法性

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <algorithm>
  6 #include <vector>
  7 #include <queue>
  8 #include <stack>
  9 inline void read(int &x){x = 0;char ch = getchar();char c = ch;while(ch < ‘0‘ || ch > ‘9‘)c = ch, ch = getchar();while(ch <= ‘9‘ && ch >= ‘0‘)x = x * 10 + ch - ‘0‘, ch = getchar();if(c == ‘-‘)x = -x;}
 10 inline int max(int a, int b){return a > b ? a : b;}
 11
 12 const int INF = 0x3f3f3f3f;
 13 const long long MOD = 100000000;
 14 const int MAXN = 100 + 10;
 15 const int MAXM = 10 + 5;
 16
 17 int n,m;
 18 int g[MAXN], k, s[100];
 19 int ans;int dp[MAXN][100][100];int num[100];
 20
 21 //找出二进制x中1的个数
 22 inline int count(int x)
 23 {
 24     int tmp = 0;
 25     while(x)
 26     {
 27         tmp ++;
 28         x &= (x - 1);
 29     }
 30     return tmp;
 31 }
 32
 33 //判断状态在水平方向上是否合法
 34 inline int ok(int x)
 35 {
 36     if(x & (x << 1))return 0;
 37     if(x & (x << 2))return 0;
 38     return 1;
 39 }
 40
 41 //判断状态x是否与第i行匹配
 42 inline bool fit(int x, int i)
 43 {
 44     if(x & g[i])return 0;
 45     return 1;
 46 }
 47
 48 //初始化某一行所有可行的状态
 49 inline void inits()
 50 {
 51     for(int i = 0;i < (1 << m);++ i)
 52         if(ok(i))s[++k] = i, num[k] = count(i);
 53 }
 54
 55 //初始化第i行的不可走状态
 56 inline void initg()
 57 {
 58     for(int i = 1;i <= n;++ i)
 59     {
 60         for(int j= 1;j <= m;++ j)
 61         {
 62             char c = getchar();
 63             while(c != ‘H‘ && c != ‘P‘)c = getchar();
 64             if(c == ‘H‘)g[i] += (1 << (m - j));
 65         }
 66     }
 67 }
 68
 69 //初始化第一行的状态  dp、s: 0表示不放大炮,1表示放大炮  g:0表示可放大炮,1表示不可放大炮
 70 inline void initdp()
 71 {
 72     //s中第一个状态是0,一定合法
 73     for(int i = 1;i <= k;++ i)
 74         if(fit(s[i], 1))
 75             dp[1][1][i] = num[i], ans = max(ans, dp[1][1][i]);
 76 }
 77
 78 inline void DP()
 79 {
 80     for(int i = 2;i <= n;++ i)
 81     {
 82         for(int j = 1;j <= k;++ j)
 83         {
 84             if(!fit(s[j],i))continue;
 85
 86             for(int pre = 1;pre <= k;++ pre)
 87             {
 88                 if((s[pre] & s[j]) || (s[pre] & g[i - 1]))continue;
 89
 90                 for(int pre2 = 1;pre2 <= k;++ pre2)
 91                 {
 92                     if((s[pre2] & s[j]) || (s[pre2] & s[pre]) || (s[pre2] & g[i - 2]))continue;
 93                     dp[i][pre][j] = max(dp[i][pre][j], dp[i - 1][pre2][pre] + num[j]);
 94                 }
 95                 if(i == n)
 96                     ans = max(ans, dp[i][pre][j]);
 97             }
 98         }
 99     }
100 }
101
102 inline void out()
103 {
104     printf("%d", ans);
105 }
106
107 int main()
108 {
109     read(n);read(m);
110     initg();
111     inits();
112     initdp();
113     DP();
114     out();
115     return 0;
116 }

时间: 2024-10-11 21:23:54

洛谷P2704 炮兵阵地的相关文章

状压DP 洛谷P2704 炮兵阵地

P2704 炮兵阵地 题目描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图.在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队):一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格.图上其它白色网格

【洛谷P2704【NOI2001】】炮兵阵地

题目描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图.在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队):一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格.图上其它白色网格均攻击不到.从图上可见

洛谷 P2709 BZOJ 3781 小B的询问

题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. 输入输出格式 输入格式: 第一行,三个整数N.M.K. 第二行,N个整数,表示小B的序列. 接下来的M行,每行两个整数L.R. 输出格式: M行,每行一个整数,其中第i行的整数表示第i个询问的答案. 输入输出样例 输入样例#1: 6 4 3 1 3 2 1 1 3

洛谷1231 教辅的组成

洛谷1231 教辅的组成 https://www.luogu.org/problem/show?pid=1231 题目背景 滚粗了的HansBug在收拾旧语文书,然而他发现了什么奇妙的东西. 题目描述 蒟蒻HansBug在一本语文书里面发现了一本答案,然而他却明明记得这书应该还包含一份练习题.然而出现在他眼前的书多得数不胜数,其中有书,有答案,有练习册.已知一个完整的书册均应该包含且仅包含一本书.一本练习册和一份答案,然而现在全都乱做了一团.许多书上面的字迹都已经模糊了,然而HansBug还是可

洛谷教主花园dp

洛谷-教主的花园-动态规划 题目描述 教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都不一样,一些树可能会因为不适合这个位置的土壤而损失观赏价值. 教主最喜欢3种树,这3种树的高度分别为10,20,30.教主希望这一圈树种得有层次感,所以任何一个位置的树要比它相邻的两棵树的高度都高或者都低,并且在此条件下,教主想要你设计出一套方案,使得观赏价值之和最高. 输入输出格式 输入格式: 输入文件garden.in的第1行为一个正整数n,表示需要种的

洛谷 P2801 教主的魔法 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=2801 题目描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.…….N. 每个人的身高一开始都是不超过1000的正整数.教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W.(虽然L=R时并不

洛谷P1466 集合 Subset Sums

洛谷P1466 集合 Subset Sums这题可以看成是背包问题 用空间为 1--n 的物品恰好填充总空间一半的空间 有几种方案 01 背包问题 1.注意因为两个交换一下算同一种方案,所以最终 要 f [ v ] / 2 2.要开 long long 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string&g

洛谷P1160 队列安排 链表

洛谷P1160 队列安排   链表 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <cstdlib> 5 #include <string> 6 #include <algorithm> 7 #include <iomanip> 8 #include <iostream> 9 using namespace std

洛谷 P3367 并查集模板

#include<cstdio> using namespace std; int n,m,p; int father[2000001]; int find(int x) { if(father[x]!=x) father[x]=find(father[x]); return father[x]; } void unionn(int i,int j) { father[j]=i; } int main() { scanf("%d%d",&n,&m); for