题目大意:
- 在一个有一个会以速度 2 自动分裂的 ghost 的有墙壁的迷宫里
- 给两个速度分别为1,3的点 G , M , 问能否在不碰到 ghost 的情况下相遇
- 在一秒内,ghost分裂后 , G , M 再移动
- 若可以相遇输出时间,不能相遇输出-1
解题过程:
- 刚开始写了一个纯的bfs , 对 ghost 的到每个地方的时间bfs求出来,然后再bfs求出其中一个人合法到达每个地方的时间,再用bfs判断另一个人是否可以合法地碰到前面那个人,结果超时了.
- 优化:
- (1)ghost的位置其实是曼哈顿距离,省去了第一次的bfs
- (2)两个人的位置交替bfs,即双向bfs,又省去了一次bfs
- *
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include <cstring>
#define rep(i,l,p) for (int i = l;i<=p;i++)
#define drep(i,p,l) for (int i = p;i>=l;i--)
#define fread() freopen("in.txt","r",stdin)
using namespace std;
const int dx[4] = {0,0,1,-1};
const int dy[4] = {1,-1,0,0};
int n,m,step;
char Map[805][805];
struct Node
{
int x,y;
Node(int _,int __):x(_),y(__){}
Node(){}
}gg,mm,z[2];
bool legal(int x,int y){
rep(i,0,1) if(abs(z[i].x - x) + abs(z[i].y - y) <= 2*step ) {
return false;
}
if(x<1 || x>n || y<1 || y>m || Map[x][y] == 'X') return false;
return true;
}
bool bfs(queue<Node> &q,int num,char st,char ed){
queue<Node> qt;
rep(i,1,num){
while(!q.empty()){
int x = q.front().x,y = q.front().y;
q.pop();
if(!legal(x,y)) continue;
rep(i,0,3){
int xx = x+dx[i],yy = y+dy[i];
if(!legal(xx,yy) || Map[xx][yy]==st) continue;
if(Map[xx][yy] == ed) {
return true;
}
Map[xx][yy] = st;
qt.push(Node(xx,yy));
}
}
q = qt;
}
return false;
}
int solve(){
queue<Node> que[2];
que[0].push(gg);
que[1].push(mm);
step = 0;
while( !que[1].empty() || !que[1].empty()){
step++;
if(bfs(que[0],1,'G','M') || bfs(que[1],3,'M','G') ){
return step;
}
}
return -1;
}
inline void init(){
cin >> n >> m;
int cnt = 0;
rep(i,1,n) cin >> Map[i]+1;
rep(i,1,n){
rep(j,1,m){
if(Map[i][j] == 'Z') {z[cnt].x = i; z[cnt].y = j; cnt++;}
else if(Map[i][j] == 'G') gg.x = i,gg.y = j;
else if (Map[i][j] == 'M') mm.x = i,mm.y = j;
}
}
}
int main(int argc, char const *argv[])
{
std::ios::sync_with_stdio(false);
int T;
cin >> T;
while(T--){
init();
cout << solve() << endl;
}
return 0;
}