题意
在一个迷宫里,有一个boy和一个girl,还有两个鬼。boy每秒钟走 3 步,girl 每秒钟走 1 步,鬼每秒钟超两步内能到达的格内分身。注意,鬼可以无视墙壁。并且, 每一秒,鬼分裂boy和girl再走。如果boy或girl和鬼在一个格子里,它们会被吃掉。问在被吃掉之前boy和girl能否相遇。
思路
一开始想的是 预处理+BFS。就是先把 鬼 和 boy 到达每个点的时间求出来,然后对 girl BFS。果不其然,TLE。这个题是 双向BFS。
1.从 boy 和 girl 两个点出发,双向BFS。
2.不需要对 鬼 进行预处理,只需在到达每个点是判断点到鬼的距离即可,O(1)。
3.需要注意的一点是,输入的时候如果一个字符一个字符地读会TLE,一行一行地读就AC了。
双向DFS
其实双向dfs就是把 队列 和 dis 数组都搞成二维的,对应每一方向。然后把起点和终点分别放进一个队列里,当两个队列出现重合点时,搜索就结束了。
双向DFS较单向有很大幅度的效率提升。
题目链接
http://acm.hdu.edu.cn/showproblem.php?pid=3085
AC代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int, int> P;
const int maxn = 810;
const int inf = 0x3f3f3f3f;
const int mx[4] = {-1, 0, 1, 0};
const int my[4] = {0, 1, 0, -1};
int cas;
int n, m;
char G[maxn][maxn];
P M, W, Z0, Z1;
bool dis[2][maxn][maxn];
queue<P> qu[2];
int Abs(int x)
{
return x > 0 ? x : -x;
}
//检查点是不是安全
bool check(int x, int y, int steps)
{
if(x < 0 || x >= n || y < 0 || y >= m) return false;
if(G[x][y] == 'X') return false;
//和鬼的距离
if(Abs(x - Z0.first) + Abs(y - Z0.second) <= 2 * steps) return false;
if(Abs(x - Z1.first) + Abs(y - Z1.second) <= 2 * steps) return false;
return true;
}
//u 是队列序号,steps 是时间
bool bfs(int u, int steps)
{
int num = qu[u].size();//这一点学到了
while(num --)
{
int x = qu[u].front().first, y = qu[u].front().second;
qu[u].pop();
if(!check(x, y, steps)) continue;//因为鬼先走,所以这里还要检查一次
for(int i= 0; i< 4; i++)
{
int xx = x + mx[i], yy = y + my[i];
if(!dis[u][xx][yy] && check(xx, yy, steps))
{
if(dis[u^1][xx][yy]) return true;//会师成功
dis[u][xx][yy] = true;
qu[u].push(P(xx, yy));
}
}
}
return false;
}
int bid_bfs()
{
//初始化
memset(dis, false, sizeof dis);
while(qu[0].size()) qu[0].pop();
while(qu[1].size()) qu[1].pop();
//两个起点各自入队
dis[0][M.first][M.second] = true;
qu[0].push(M);
dis[1][W.first][W.second] = true;
qu[1].push(W);
//boy 走三步,girl 走一步
for(int i= 1; qu[0].size() || qu[1].size(); i++)
{
if(bfs(0, i)) return i;
if(bfs(0, i)) return i;
if(bfs(0, i)) return i;
if(bfs(1, i)) return i;
}
//不能会师
return -1;
}
int main()
{
cin >> cas;
while(cas --)
{
scanf("%d %d", &n, &m);
for(int i= 0; i< n; i++)
scanf(" %s", &G[i]);
Z0.first = -1;
for(int i= 0; i< n; i++)
for(int j= 0; j< m; j++)
{
if(G[i][j] == 'M') M = P(i, j);
if(G[i][j] == 'G') W = P(i, j);
if(G[i][j] == 'Z')
if(Z0.first == -1) Z0 = P(i, j);
else Z1 = P(i, j);
}
cout << bid_bfs() << endl;
}
return 0;
}