题目描述
司令部的将军们打算在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)&&((i&(i<<2))==0)&&((i&(i>>1))==0)&&((i&(i>>2))==0)
/*判断每个1左右各两个是否有1,即判断这种状态是否存在
没有连续的两个1存在,只要移一位后和原来的自己按位与,结果为0,表示正好对应的列
没有两个1同时出现的可能
*/{++k;s[k]=i;g[k]=get(i);if((i&map[1])==0) f[1][0][k]=g[k];//第一行状态为0,就是没有放置炮兵,第一行的前一行为k/*初始化第一行,i时预处理过的整数,map[1]时一行地形按位与位0,表示对这的两列不同时为1,符合炮兵摆放规则*/} //初始化第二行 for(int i=1;i<=k;++i)//枚举第一行状态 for(int j=1;j<=k;++j)//枚举第二行状态 if(((s[i]&s[j])==0)&&((s[j]&map[2])==0))  f[2][i][j]=max(f[2][i][j],f[1][0][i]+g[j]);//判断是否与地形和第一行冲突 //dp过程 for(int i=3;i<=n;++i)//枚举当前行数 for(int j=1;j<=k;++j)//枚举当前行数状态 if((map[i]&s[j])==0)//不与地形冲突 for(int p=1;p<=k;++p)//枚举前一行状态 if((s[p]&s[j])==0)//当前行状态不与前一行冲突 for(int q=1;q<=k;++q)//枚举前两行//不与前两行冲突,且前两行自身不冲突 if(((s[q]&s[p])==0)&&((s[q]&s[j])==0)) f[i][p][j]=max(f[i][p][j],f[i-1][q][p]+g[j]);for(int i=1;i<=k;++i)//枚举最后两行为结尾的情况,统计答案 for(int j=1;j<=k;++j)ans=max(f[n][i][j],ans);cout<<ans;       //输出        return 0;
}

预处理后的代码:

#include <iostream>
#include <cstring>
using namespace std;
#define MST(a, b) memset(a, b, sizeof(a));
#define CLR(a) MST(a, 0);
#define rep(x, y, z) for (int x = y; x < z; ++x)
const int INF = 0x3f3f3f3f;
int dp[101][77][77];
int sg[101];
int n, m, idx;
int s[77];
int cnt0[77];
int get_one(int x) {int cnt = 0;while(x) x &= (x-1), ++cnt;return cnt;
}
bool ok(int x) {if(x & (x << 1)) return false;if(x & (x << 2)) return false;return true;
}
void init() {idx = 0;int end = 1 << m;rep(i, 0, end) if(ok(i)) {s[idx] = i;cnt0[idx++] = get_one(i);}
}
bool valid(int i, int x) {if(sg[i] & x) return false;return true;
}
int solve() {int ans = 0;MST(dp, -1);dp[0][0][0] = 0;rep(j, 0, idx) if(valid(1, s[j])) {dp[1][j][0] = cnt0[j];ans = max(ans, dp[1][j][0]);}rep(i, 2, n+1) {rep(j, 0, idx) if(valid(i, s[j])) {rep(k, 0, idx) if(valid(i-1, s[k]) && (s[j]&s[k])==0) {int last = 0;rep(l, 0, idx) if(dp[i-1][k][l] != -1 && (s[l]&s[j])==0 && valid(i-2, s[l])) {last = max(last, dp[i-1][k][l]);}dp[i][j][k] = max(dp[i][j][k], last + cnt0[j]);if(i == n) ans = max(ans, dp[i][j][k]);}}}return ans;
}
int main(int argc, char const *argv[]) {ios::sync_with_stdio(0);cin.tie(0);cin >> n >> m;rep(i, 1, n+1) rep(j, 0, m) {char tmp; cin >> tmp;if(tmp == 'H') sg[i] |= (1 << (m-1-j));}init();cout << solve() << endl;return 0;
}

炮兵阵地图文详解NOI2001/POJ1185(状态压缩)相关推荐

  1. 图文详解jvm中的线程状态

    本文使用下面这张图详细介绍JAVA线程的六种状态 JAVA线程的六种状态详解 在java.lang.Thread类中,定义了线程的以下六种状态(同一个时刻线程只能有一种状态)  NEW(新建) 这个状 ...

  2. 计算机刷新的作用,图文详解Win8重置和刷新功能:超强自我治愈

    直接自愈,Windows8出故障之后,伴随着重置和刷新两大新功能,世上无难事了啊.微软Windows8团队今日在官方博客详细向用户解释Win8的重置和刷新PC功能,将可一键复位系统到最佳状态.视频演示 ...

  3. Git客户端图文详解如何安装配置GitHub操作流程攻略

    Git客户端图文详解如何安装配置GitHub操作流程攻略 软件应用 爱分享  3个月前 (08-15)  8896浏览  0评论 Git介绍 分布式 : Git版本控制系统是一个分布式的系统, 是用来 ...

  4. Android四大组件之——Activity的生命周期(图文详解)

        转载请在文章开头处注明本博客网址:http://www.cnblogs.com/JohnTsai       联系方式:JohnTsai.Work@gmail.com       [Andro ...

  5. Ubuntu14.04下Mongodb数据库可视化工具安装部署步骤(图文详解)(博主推荐)

    不多说,直接上干货! 前期博客 Ubuntu14.04下Mongodb(离线安装方式|非apt-get)安装部署步骤(图文详解)(博主推荐) Ubuntu14.04下Mongodb官网安装部署步骤(图 ...

  6. Linux系统7个运行级别图文详解

    Linux系统7个运行级别图文详解 当安装linux操作系统时将选择下列那一个操作 ______ A.选择 "图形登录方式" 设定系统开始运行级为4 B.选择 "文本登录 ...

  7. mysql拷贝文件安装_Mysql5.7.18的安装与主从复制图文详解

    CentOS6.7安装mysql5.7.18 1.  解压到/usr/local目录 # tar -zxvf mysql-5.7.18-linux-glibc2.5-i686.tar.gz -C /u ...

  8. mysql数据库主主_MySQL主主复制(图文详解)

    MySQL主主复制(图文详解) 发布时间:2020-07-12 23:10:25 来源:51CTO 阅读:218 作者:BonnieJason 一.实现原理 主主复制即在两台MySQL主机内都可以变更 ...

  9. Git学习系列之如何正确且高效地将本地项目上传到Github(图文详解)

    不多说,直接上干货! 首先你需要一个Github账号,所以还没有的话先去注册吧! https://github.com/ 见 如何走上更高平台分享传递干货知识:(开通个人Github面向开源及私有软件 ...

  10. storyboard(故事版)新手教程 图文详解 1.创建一个无约束的导航栏加选项卡(tabbar)故事版

    OSX系统10.10.5 Xcode版本7.1 本文图文详解如何初步使用故事版进行开发 1.打开Xcode  点击Create a new Xcode project 选择Single View Ap ...

最新文章

  1. 标准化工作取得新突破 窄带物联网商用指日可待
  2. Kubernetes Helm入门指南
  3. CMake 指定安装目录
  4. moss中修改master页需要注意的地方
  5. python序列化持久化需要注意的一个问题
  6. SQL Server数据库-限制返回行数
  7. android4.4 hls,Android VideoView直播电视流(HLS)
  8. mySQL用alter使列为空_我可以配置MySQL,以便新添加的列默认允许空值吗?
  9. 华南理工计算机研究生专业课,华南理工大学(专业学位)计算机技术研究生考试科目和考研参考书目...
  10. 2018/2/28 省选模拟赛 40分
  11. POJ 3756 多边形内角和
  12. 计算机硬件故障有哪些现象,计算机常见硬件故障症状现象分析及解决办法
  13. h3c 出口路由器mac地址过滤
  14. HTTP协议原理详解
  15. arduino: 各种Arduino基础器件的用法图
  16. 使用WarZone联机对战横扫千军(TA)指南
  17. Python pandas.DataFrame.expanding函数方法的使用
  18. wordpress 建站15个注意事项
  19. 期刊发表要求大概有哪些
  20. 2.php函数,PHP函数索引(2)

热门文章

  1. UE4 Pak包热更新
  2. tcpreplay linux,Linux——Tcpreplay
  3. java if里面并列_多个if语句并列-两个if语句并列-if语句两个并列条件怎么表示
  4. python“渡劫”进阶期(继承、多态、私有化、异常捕获、类属性和类方法)
  5. Eloquen模型的具体使用方法
  6. 【蓝桥杯】基础练习 字母图形
  7. 【数藏之家】盘点周杰伦的NFT之路,NFT如何借明星之力形成“破圈效应”?
  8. 使用高德地图api在页面中展示地图
  9. Illegal base64 character 20
  10. 《成都》钢琴谱,带指法和歌词