UVA-11624 两次BFS
思路
一开始想的时候就是分别进行BFS,然后对边界上的时间进行推断,如果人到这个点的时间小于火到这个点的时间,那么就是可以逃脱,但是忽略了很多细节,边界只推导了两个,然后初始化的时候每个点都是0,边界在不可达的情况下是错误的,后来更改了一下还是不对。
另外bfs的顺序也应该注意,应该是先让火进行BFS,然后人进行BFS的时候应该判断该点是否是可达的,如果可达才能够进行下一步的操作(为什么不能让火进行BFS,人进行BFS,然后推断一下点是否合法?,我觉得这个做法也行,因为BFS进行的就是最短路,如果该点不可达,那么BFS上火和人的时间一定是有一个大小关系的,即使人BFS过了这个点,火的时间也是远大于人的),最好的做法就是让火进行BFS,然后人再进行BFS判断点是否可达,如果当前队头已经可以出界,则判断YES,否则NO。
Code
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
const int N = 1e3 + 10;
int dx[] = {0, -1, 1, 0}, dy[] = {1, 0, 0, -1};
struct node {
int jt = 0, ft = 0;
}d[N][N];
int n, m, sx, sy, ans;
char a[N][N];
queue<pair<int, int>> q2;
void bfs() {
while(q2.size()) {
pair<int, int> t = q2.front(); q2.pop();
for (int i = 0; i <= 3; i ++) {
int x = t.first + dx[i], y = t.second + dy[i];
if(x >= 1 && x <= n && y >= 1 && y <= m && a[x][y] != '#' && d[x][y].ft == -1) {
d[x][y].ft = d[t.first][t.second].ft + 1;
q2.push({x, y});
}
}
}
}
void bfs2() {
queue<pair<int, int>> q1;
q1.push({sx, sy});
d[sx][sy].jt = 1;
while(q1.size()) {
pair<int, int> t = q1.front(); q1.pop();
if(t.first == 1 || t.second == 1 || t.first == n || t.second == m) {
ans = min(ans, d[t.first][t.second].jt);
return;
}
for (int i = 0; i <= 3; i ++) {
int x = t.first + dx[i], y = t.second + dy[i];
if(x >= 1 && x <= n && y >= 1 && y <= m && a[x][y] != '#' && d[x][y].jt == -1) {
d[x][y].jt = d[t.first][t.second].jt + 1;
if(d[x][y].jt < d[x][y].ft || (d[x][y].ft == -1))
q1.push({x, y});
}
}
}
}
int main() {
int _; cin >> _;
while (_ --) {
cin >> n >> m;
while(q2.size()) q2.pop();
memset(d, -1, sizeof d);
ans = 0x3f3f3f3f;
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= m; j ++) {
cin >> a[i][j];
if (a[i][j] == 'J') sx = i, sy = j;
else if (a[i][j] == 'F') {
d[i][j].ft = 1;
q2.push({i, j});
}
}
}
bfs();
bfs2();
if (ans == 0x3f3f3f3f) cout << "IMPOSSIBLE";
else cout << ans;
cout <<"\n";
}
}