噩梦(双向BFS)
Posted 海边微风起
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了噩梦(双向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 + 100; const int MAXM = 3e3 + 10; template < typename T > inline void read(T &x) { x = 0; T ff = 1, ch = getchar(); while(!isdigit(ch)) { if(ch == \'-\') ff = -1; ch = getchar(); } while(isdigit(ch)) { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); } x *=ff; } template < typename T > inline void write(T x) { if(x < 0) putchar(\'-\'), x = -x; if(x > 9) write(x / 10); putchar(x % 10 + \'0\'); } int T, n, m; int vis[MAXM][MAXM]; int dx[5] = {1, 0, -1, 0}; int dy[5] = {0, 1, 0, -1}; char ch[MAXM][MAXM]; pair < int, int > boy, girl, ghost[2]; // 梁神我的算法进阶是不是在你那 -- msm inline bool check(int xx, int yy, int dis) { if(xx < 0 || xx >= n || yy < 0 || yy >= m || ch[xx][yy] == \'X\') return false; for(int i = 0; i < 2; ++i) { if(abs(xx - ghost[i].first) + abs(yy - ghost[i].second) <= 2 * dis) return false; } return true; } inline int BFS() { memset(vis, 0, sizeof(vis)); queue < pair < int, int > > qb, qg; qb.push(boy); qg.push(girl); int dis = 0; while(!qb.empty() || !qg.empty()) { ++dis; for(int i = 0; i < 3; ++i) { int len = qb.size(); for(int j = 0; 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 = 0; k < 4; ++k) { int u = a + dx[k], v = b + dy[k]; if(check(u, v, dis)) { if(vis[u][v] == 2) return dis; if(!vis[u][v]) { vis[u][v] = 1; qb.push({u, v}); } } } } } int len = qg.size(); for(int i = 0; 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 = 0; k < 4; ++k) { int u = a + dx[k], v = b + dy[k]; if(check(u, v, dis)) { if(vis[u][v] == 1) return dis; if(!vis[u][v]) { vis[u][v] = 2; qg.push({u, v}); } } } } } return -1; } int main() { read(T); while(T--) { read(n); read(m); for(int i = 0; i < n; ++i) { scanf("%s", ch[i]); } int tot = 0; for(int i = 0; i < n; ++i) { for(int j = 0; 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 0; }
以上是关于噩梦(双向BFS)的主要内容,如果未能解决你的问题,请参考以下文章