噩梦(双向BFS)
给定一张N*M的地图,地图中有1个男孩,1个女孩和2个鬼。
字符“.”表示道路,字符“X”表示墙,字符“M”表示男孩的位置,字符“G”表示女孩的位置,字符“Z”表示鬼的位置。
男孩每秒可以移动3个单位距离,女孩每秒可以移动1个单位距离,男孩和女孩只能朝上下左右四个方向移动。
每个鬼占据的区域每秒可以向四周扩张2个单位距离,并且无视墙的阻挡,也就是在第k秒后所有与鬼的曼哈顿距离不超过2k的位置都会被鬼占领。
注意: 每一秒鬼会先扩展,扩展完毕后男孩和女孩才可以移动。
求在不进入鬼的占领区的前提下,男孩和女孩能否会合,若能会合,求出最短会合时间。
输入格式
第一行包含整数T,表示共有T组测试用例。
每组测试用例第一行包含两个整数N和M,表示地图的尺寸。
接下来N行每行M个字符,用来描绘整张地图的状况。(注意:地图中一定有且仅有1个男孩,1个女孩和2个鬼)
输出格式
每个测试用例输出一个整数S,表示最短会合时间。
如果无法会合则输出-1。
每个结果占一行。
emmmmm, 当时就打了个测试程序就回班了, 回来之后看到我的代码里有这个东西:

啊啊啊, 孟神, 你的算法进阶真不是我拿的啊。
进入正题--
求步数的话我们很容易想到BFS, 但这是两个人, 其实也很容易想到双向BFS, 创建两个队列, 在合法的状态下同时搜索, 当一个人搜索到另一个点人访问过的点时, 此时的步数就是最少步数;
#include <bits/stdc++.h> using namespace std; typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 5e5 + ;
const int MAXM = 3e3 + ; template < typename T > inline void read(T &x) {
x = ; T ff = , ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') ff = -;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << ) + (x << ) + (ch ^ );
ch = getchar();
}
x *=ff;
} template < typename T > inline void write(T x) {
if(x < ) putchar('-'), x = -x;
if(x > ) write(x / );
putchar(x % + '');
} int T, n, m;
int vis[MAXM][MAXM];
int dx[] = {, , -, };
int dy[] = {, , , -};
char ch[MAXM][MAXM];
pair < int, int > boy, girl, ghost[]; // 梁神我的算法进阶是不是在你那 -- msm inline bool check(int xx, int yy, int dis) {
if(xx < || xx >= n || yy < || yy >= m || ch[xx][yy] == 'X') return false;
for(int i = ; i < ; ++i) {
if(abs(xx - ghost[i].first) + abs(yy - ghost[i].second) <= * dis) return false;
}
return true;
} inline int BFS() {
memset(vis, , sizeof(vis));
queue < pair < int, int > > qb, qg;
qb.push(boy);
qg.push(girl);
int dis = ;
while(!qb.empty() || !qg.empty()) {
++dis;
for(int i = ; i < ; ++i) {
int len = qb.size();
for(int j = ; j < len; ++j) {
pair < int, int > x;
x = qb.front();
qb.pop();
int a = x.first, b = x.second;
if(!check(a, b, dis)) continue;
for(int k = ; k < ; ++k) {
int u = a + dx[k], v = b + dy[k];
if(check(u, v, dis)) {
if(vis[u][v] == ) return dis;
if(!vis[u][v]) {
vis[u][v] = ;
qb.push({u, v});
}
}
}
}
}
int len = qg.size();
for(int i = ; i < len; ++i) {
pair < int, int > x;
x = qg.front();
qg.pop();
int a = x.first, b = x.second;
if(!check(a, b, dis)) continue;
for(int k = ; k < ; ++k) {
int u = a + dx[k], v = b + dy[k];
if(check(u, v, dis)) {
if(vis[u][v] == ) return dis;
if(!vis[u][v]) {
vis[u][v] = ;
qg.push({u, v});
}
}
}
} }
return -;
} int main() {
read(T);
while(T--) {
read(n); read(m);
for(int i = ; i < n; ++i) {
scanf("%s", ch[i]);
}
int tot = ;
for(int i = ; i < n; ++i) {
for(int j = ; j < m; ++j) {
if(ch[i][j] == 'M') boy = {i, j};
else if(ch[i][j] == 'G') girl = {i, j};
else if(ch[i][j] == 'Z') ghost[tot++] = {i ,j};
}
}
write(BFS());
puts("");
}
return ;
}
噩梦(双向BFS)的更多相关文章
- POJ1915Knight Moves(单向BFS + 双向BFS)
题目链接 单向bfs就是水题 #include <iostream> #include <cstring> #include <cstdio> #include & ...
- HDU 3085 Nightmare II 双向bfs 难度:2
http://acm.hdu.edu.cn/showproblem.php?pid=3085 出的很好的双向bfs,卡时间,普通的bfs会超时 题意方面: 1. 可停留 2. ghost无视墙壁 3. ...
- POJ 3170 Knights of Ni (暴力,双向BFS)
题意:一个人要从2先走到4再走到3,计算最少路径. 析:其实这个题很水的,就是要注意,在没有到4之前是不能经过3的,一点要注意.其他的就比较简单了,就是一个双向BFS,先从2搜到4,再从3到搜到4, ...
- [转] 搜索之双向BFS
转自:http://www.cppblog.com/Yuan/archive/2011/02/23/140553.aspx 如果目标也已知的话,用双向BFS能很大程度上提高速度. 单向时,是 b^le ...
- 双向BFS
转自“Yuan” 如果目标也已知的话,用双向BFS能很大提高速度 单向时,是 b^len的扩展. 双向的话,2*b^(len/2) 快了很多,特别是分支因子b较大时 至于实现上,网上有些做法是用两个 ...
- HDU 3085 Nightmare Ⅱ (双向BFS)
Nightmare Ⅱ Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- HDU 3085 Nightmare Ⅱ 双向BFS
题意:很好理解,然后注意几点,男的可以一秒走三步,也就是三步以内的都可以,鬼可以穿墙,但是人不可以,鬼是一次走两步 分析:我刚开始男女,鬼BFS三遍,然后最后处理答案,严重超时,然后上网看题解,发现是 ...
- POJ 3126 Prime Path 解题报告(BFS & 双向BFS)
题目大意:给定一个4位素数,一个目标4位素数.每次变换一位,保证变换后依然是素数,求变换到目标素数的最小步数. 解题报告:直接用最短路. 枚举1000-10000所有素数,如果素数A交换一位可以得到素 ...
- Hdu1401-Solitaire(双向bfs)
Solitaire is a game played on a chessboard 8x8. The rows and columns of the chessboard are numbered ...
随机推荐
- python元类深入理解
1.python 中的类 在python中,类也是一个对象,只不过这个对象拥有生成实例的能力,我们一般使用class XXX来定义一个类,在python解释器执行到这个地方的时候会自动创建出这个对象, ...
- 2019牛客暑期多校训练营(第三场)H题目
题意:给你一个N×N的矩阵,求最大的子矩阵 满足子矩阵中最大值和最小值之差小于等于m. 思路:这题是求满足条件的最大子矩阵,毫无疑问要遍历所有矩阵,并判断矩阵是某满足这个条件,那么我们大致只要解决两个 ...
- jsp数据交互(一).3
引入的文件如果是jsp则应定义为***.jspf文件,如果其他文件可定义为***.inc文件,即include file. jsp:include是既可以静态包含又可以动态包含,用jsp:includ ...
- 文件A的内容复制到B
1.脚本 from sys import argvfrom os.path import existsscript,from_file,to_file = argvprint("Copy f ...
- Linux Qt使用POSIX多线程条件变量、互斥锁(量)
今天团建,但是文章也要写.酒要喝好,文要写美,方为我辈程序员的全才之路.嘎嘎 之前一直在看POSIX的多线程编程,上个周末结合自己的理解,写了一个基于Qt的用条件变量同步线程的例子.故此来和大家一起分 ...
- 林大妈的JavaScript基础知识(三):JavaScript编程(3)原型
在一般的编程语言中,我们使用继承来复用代码,做成良好的数据结构.而在JavaScript中,我们使用原型来实现以上的需求.由于JavaScript专注于对象而摒弃了类,我们要明白原型和继承的确是有差异 ...
- Cell Phone Networ (树形dp-最小支配集)
目录 Cell Phone Networ (树形dp-最小支配集) 题意 思路 题解 Cell Phone Networ (树形dp-最小支配集) Farmer John has decided to ...
- Docker——理解好镜像和容器的关系
关注公众号,大家可以在公众号后台回复“博客园”,免费获得作者 Java 知识体系/面试必看资料. 镜像也是 docker 的核心组件之一,镜像时容器运行的基础,容器是镜像运行后的形态.前面我们介绍了 ...
- scrapy框架与python爬虫
- .lib .dll 区别介绍、使用(dll的两种引入方式)
.lib .dll文件都是程序可直接引用的文件,前者就是所谓的库文件,后者是动态链接库(Dynamic Link Library)也是一个库文件.而.pdb则可以理解为符号表文件.DLL(Dynami ...