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

如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。 现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。
输入格式
第一行包含两个由空格分割开的正整数,分别表示N和M;
接下来的N行,每一行含有连续的M个字符(‘P’或者‘H’),中间没有空格。按顺序表示地图中每一行的数据。N≤100;M≤10。
输出格式
仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。
输入样例:
5 4
PHPP
PPHH
PPPP
PHPP
PHHP
输出样例:
6
算法思路:
解法一:
因为每个位置能否放置炮兵与它上面两行对应位置上是否放置炮兵有关,所以在向第i行的状态转移时,需要知道第i-1行和第i-2行的状态。我们把每一行的状态看作一个M位二进制数,用一个0~2M-1之间的十进制整数存储,其中第p(0≤p<M)位为1表示该行第p列放置了炮兵,为0则表示没有放置炮兵。
我们在DP前预处理出集合S,存储“相邻两个1的距离不小于3”的所有M位二进制数,这些二进制数代表每一行中两个炮兵的距离不能小于3。
设count(x)表示M位二进制数x中1的个数。
设valid(i, x)表示M位二进制数x属于集合S,并且x中的每个1对应在地图第i行中的位置都是平原。
设F[i,j,k]表示第i行压缩后的状态为j,第i-1行压缩后的状态为k时,前i行最多能摆放多少个炮兵。

F[i,j,k]表示第i行状态为j,第i-1行状态为k ,那么j&k=0表示这两行的摆放炮兵不冲突,那么k的状态不同,对应的j的状态就不同,所以的枚举j和k。
上一行i-1的状态为k,那么就枚举i-1行上一行的状态l,保证l和k不冲突,再保证l和j不冲突,这样就保证了第i行j和第i-1行k,和第i-2行l都不冲突。
理解了上述,代码就好写了,对于第i行枚举j、枚举k、枚举l三层循环,当然j,k,l属于集合S,并且x中的每个1对应在地图第i行中的位置都是平原。
并且 j&k=0且j&l=0
j&l=0表示这两个整数对应的列没有两个都是1,只有两个都是1按位与才是1.
初值:F[0,0,0]=0,其余为负无穷。
目标:

完整代码:
#include<iostream>
#include<cstdio>
using namespace std;
int n,m,k;
int s[1005],g[1005];
int f[102][1005][1005],ans;
char ma[103];
int map[103];
int get(int x)//计算某一状态含有多少个1(即有多少个炮兵)
{
int e=0;
while(x>0)
{
++e;
x-=x&(-x);
}
return e;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;++i)
/*读入地图,将山地(不能放兵)的地方设为1 ,同时把一行地形
转化为一个m为二进制数所对应的整数。*/
{
scanf("%s",ma);
for(int j=0;j<m;++j)
if(ma[j]=='H') map[i]+=1<<j;
}
for(int i=0;i<=(1<<m)-1;++i)
//枚举所有的状态0-2^m-1,处理出满足条件的集合s
if(((i&(i<<1))==0)&&
炮兵部署算法

本文介绍了一个基于动态规划的算法,用于解决在特定地形条件下,如何最大化部署炮兵部队数量的问题。算法通过预处理地形和炮兵攻击范围,利用二进制状态压缩技巧,实现了高效的求解。
最低0.47元/天 解锁文章
1401

被折叠的 条评论
为什么被折叠?



