题意:有两只鬼,一个男孩女孩被困在迷宫中,男孩每秒可以走三步,女孩只能1步,鬼可以两步且可以通过墙。问男孩女孩是否可以在鬼抓住他们之前会合?

注意:每秒开始鬼先移动,然后两人开始移动。

思路:以男孩和女孩为起点进行双向bfs,鬼由于可以穿墙可以直接通过曼哈顿距离判断当前位置是否合法。注意在处理男孩移动的时,必须加入一点技巧,否则处理状态太多就会超时。我用的一种比较笨的方法处理男孩的移动结果TLE了。

AC代码: 405ms

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;

const int maxn = 800 + 5;
char G[maxn][maxn];
int vis[2][maxn][maxn];
int n, m;

struct node{
	int x, y;
	node() {
	}
	node(int x, int y): x(x), y(y){
	}
};

const int dx[] = {0,0,-1,1};
const int dy[] = {-1,1,0,0}; 

bool is_ghost(int x, int y, int step, vector<node> &p) {
	for(int i = 0; i < p.size(); ++i) {
		int px = p[i].x, py = p[i].y;
		int man = abs(x - px) + abs(y - py); //曼哈顿距离
		if(step * 2 >= man) return false;
	}
	return true;
}

queue<node>q[2];
vector<node>per, ghost;

int bfs(int c, int step) { //共有四个起点
	int num = q[c].size();
	while(num--) { //清空上一次的移动位置
		node p = q[c].front();
		q[c].pop();
		int x = p.x, y = p.y;
		if(!is_ghost(x, y, step + 1, ghost)) continue;
		for(int i = 0; i < 4; ++i) {
			int px = x + dx[i], py = y + dy[i];
			if(px < 0 || py < 0 || px >= n || py >= m) continue;
			if(vis[c][px][py] || G[px][py] == 'X' || !is_ghost(px, py, step + 1, ghost)) continue;
			if(vis[1 - c][px][py]) return 1; //找到对方
			q[c].push(node(px, py));
			vis[c][px][py] = 1;
		}
	}
	return 0;
}

int solve() {
	per.clear();
	ghost.clear();
	while(!q[0].empty()) q[0].pop();
	while(!q[1].empty()) q[1].pop();
 	memset(vis, 0, sizeof(vis));
	for(int i = 0; i < n; ++i)
	for(int j = 0; j < m; ++j) {
		if(G[i][j] == 'M') {
			per.push_back(node(i, j));
			vis[0][i][j] = 1;
			q[0].push(node(i, j));
		}
		else if(G[i][j] == 'G') {
			per.push_back(node(i, j));
			q[1].push(node(i, j));
			vis[1][i][j] = 1;
		}
		else if(G[i][j] == 'Z') {
			ghost.push_back(node(i, j));
		}
	}
	for(int i = 0; i < 2; ++i) {
		if(!is_ghost(per[i].x, per[i].y, 1, ghost)) return -1;
	}
	int step = -1;
	while(!q[0].empty() && !q[1].empty()) {
		++step;
		for(int i = 0; i < 3; ++i) {
			if(bfs(0, step)) return step + 1;
 		}
 		if(bfs(1, step)) return step + 1;
	}
	return -1;
}

int main() {
	int T;
	scanf("%d", &T);
	while(T--) {
		scanf("%d%d", &n, &m);
		for(int i = 0; i < n; ++i) scanf("%s", G[i]);
		printf("%d\n", solve());
	}
	return 0;
}

如有不当之处欢迎指出!

HDU - 3085 双向BFS + 技巧处理 [kuangbin带你飞]专题二的更多相关文章

  1. HDU - 3567 Eight II (bfs预处理 + 康托) [kuangbin带你飞]专题二

    类似HDU1430,不过本题需要枚举X的九个位置,分别保存状态,因为要保证最少步数.要保证字典序最小的话,在扩展节点时,方向顺序为:down, left, right, up. 我用c++提交1500 ...

  2. HDU - 3567 IDA* + 曼哈顿距离 + 康托 [kuangbin带你飞]专题二

    这题难度颇大啊,TLE一天了,测试数据组数太多了.双向广度优先搜索不能得到字典序最小的,一直WA. 思路:利用IDA*算法,当前状态到达目标状态的可能最小步数就是曼哈顿距离,用于搜索中的剪枝.下次搜索 ...

  3. 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开

    [kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...

  4. HDU - 3533 bfs [kuangbin带你飞]专题二

    看了好久的样例才看懂. 题意:有一个人要从(0,0)走到(n,m),图中有k个碉堡,每个碉堡可以向某个固定的方向每隔t秒放一次炮,炮弹不能穿越另一个碉堡,会被阻挡.人在移动的过程中不会被炮弹打到,也就 ...

  5. HDU - 1067 Gap (bfs + hash) [kuangbin带你飞]专题二

    题意:    起初定28张卡牌的排列,把其中11,  21, 31, 41移动到第一列,然后就出现四个空白,每个空白可以用它的前面一个数的下一个数填充,例如43后面的空格可以用44填充,但是47后面即 ...

  6. HDU - 2102 A计划 (BFS) [kuangbin带你飞]专题二

    思路:接BFS判断能否在限制时间内到达公主的位置,注意如果骑士进入传送机就会被立即传送到另一层,不会能再向四周移动了,例如第一层的位置(x, y, 1)是传送机,第二层(x, y, 2)也是传送机,这 ...

  7. 【算法系列学习】[kuangbin带你飞]专题二 搜索进阶 D - Escape (BFS)

    Escape 参考:http://blog.csdn.net/libin56842/article/details/41909459 [题意]: 一个人从(0,0)跑到(n,m),只有k点能量,一秒消 ...

  8. HDU - 1043 A* + 康托 [kuangbin带你飞]专题二

    这题我第一次用的bfs + ELFhash,直接TLE,又换成bfs + 康托还是TLE,5000ms都过不了!!我一直调试,还是TLE,我才发觉应该是方法的问题. 今天早上起床怒学了一波A*算法,因 ...

  9. POJ - 3126 bfs + 素数筛法 [kuangbin带你飞]专题一

    题意:给定两个四位素数作为终点和起点,每次可以改变起点数的某一位,且改变后的数仍然是素数,问是否可能变换成终点数字? 思路:bfs搜索,每次改变四位数中的某一位.素数打表方便判断新生成的数是否是素数. ...

随机推荐

  1. Python程序的执行方式

    Python代码有两种执行方式: 一.文件执行 二.交互器执行(推荐) 一.文件执行 1.用 notepad++ 或 Sublime Text,甚至 写字本创建一个文件. 2.比如:print('He ...

  2. sed 变量替换和Linux的特殊符号大全

    1 sed支持两种方式的变量替换,建议使用下面的第二种,比较简单 这样就可以给变量a赋值很多特殊字符了,比如 赋值a='!@#¥%……' sed -n 's/echo/'"$a"' ...

  3. JDK 中的设计模式应用实例

      在 JDK(Java Development Kit)类库中,开发人员使用了大量设计模式,正因为如此,我们可以在不修改 JDK 源码的前提下开发出自己的应用软件.研究 JDK 类库中的模式实例也不 ...

  4. jsp中 scope="application" 表示

    jsp中 <jsp:useBean id="countbean" scope="application" class="count.counte ...

  5. Matlab产生TestBeach所需要的波形数据

    在用vivado仿真的时候,很多情况下需要自己产生波形来代替AD采样波形.以前的做法都是用DDS内部产生所需要的波形来模仿外部输入,后来发现这种做法不仅麻烦,而且不易修改,对仿真很不友好.于是改用ma ...

  6. 【Shell脚本学习指南笔记】重定向文件描述符 2>&1

    如: make > results 2>&1 重定向 > results让文件描述符1(标准输出)作为文件results,接下来的重定向2>&1有两个部分.2& ...

  7. c#后台调用API

    前两周赶上项目第一个版本上线,着实忙了一把,毕竟只有两个人负责.如今已完结,总算喘了一口气,现在任务就是写API.测API,许久之前写过JS前台调用 项目API,也写过后台调用开放的手机号归属地查询, ...

  8. 刚买个炼狱蝰蛇1800dpi的下完驱动提示没有发现鼠标

    2017-02-19补充:可以下载下面的程序 ,也可以访问 http://cn.razerzone.com/synapse/  下载雷云 也可解决问题 ------------------------ ...

  9. mysql基本了解

    数据库--MySql 数据仓库.就与我们之前学过的纯文本,properties这些技术一样.用来保存数据.并提供对数据进行增删改查的操作.我们以后做项目时,项目中的数据都是保存在数据库中的.//--- ...

  10. DOM中对象的获得

    DOM的所有对象会在页面打开时,由浏览器页面创建. 浏览器把dom定点对象Document对像的引用交给了window对象. 1.document对象的获得    var doc = window.d ...