UVA - 11624
题意:joe在一个迷宫里,迷宫的一些部分着火了,火势会向周围四个方向蔓延,joe可以向四个方向移动。火与人的速度都是1格/1秒,问j能否逃出迷宫,若能输出最小时间。
题解:先考虑模拟火,肯定是bfs(每次把同一时间着火的格子pop出来,再将它们周围的格子的t加一push进去)
然后考虑怎么模拟人,现在人处在一个会变化的迷宫中。貌似很复杂。
我们可以考虑t时刻的地图(假设我们bfs人的位置),着火的地方相当于墙壁,已经走过的地方也相当于墙壁(因为不可能回到已经走过的地方,这样要么出不去,要么走了回头路导致时间变长)。队列中存着当前时刻所有人可以到达的位置。考虑我们可以走的位置,除了边界与墙壁,如果我们知到一秒后哪些位置会着火,我们就不会走那些格子(否则就烧死了)。
于是便得到了一个算法,先让火烧一秒,然后人bjs一步,再烧1秒,再走一步。。。。
坑:一开始我先让人走一步,结果完全无法模拟人被火烧到的情况;
用queue的的时候老报错,总是pop空栈(因为没有考虑第一个与同一时刻的最后一个的特殊情况,结果写了一个很混乱的逻辑判断)
正确的方法是:
f v = F.front();
if (v.t == t) {...} else{return;}
#define _CRT_SECURE_NO_WARNINGS #include#include #include #include<string> #include #include<string.h> #include using namespace std; typedef long long ll; const int maxn = 10000 + 5; //模拟F,深搜J, //F有多个,J一个 struct f { int x, y, t; f(int x = 0, int y = 0, int t = 0) :x(x), y(y), t(t) {} }; int dir[4][2] = { 0,1, 0,-1, 1,0, -1,0 }; char map[maxn][maxn]; int vis[maxn][maxn], fired[maxn][maxn]; queue F, J; int R, C; int flag = 1; int cnt = 0, square = 0; int T = 0; bool check(int x, int y) { if (map[x][y] == '#' || R < x || x <= 0 || y <= 0 || C < y)return 1; else return 0; } void spread(int t) {//fire at (x,y) spread.//bfs1层 while (!F.empty()) { f v = F.front(); if (v.t == t) { map[v.x][v.y] = '#'; F.pop(); for (int i = 0; i < 4; i++) { int dx = v.x + dir[i][0], dy = v.y + dir[i][1]; if (check(dx, dy))continue; map[dx][dy] = '#'; F.push(f(dx, dy, v.t + 1)); } } else return; } } void bfs(int t) {//J runs at t while (!J.empty()) { f v = J.front(); if (v.t == t) { J.pop(); for (int i = 0; i < 4; i++) { int dx = v.x + dir[i][0], dy = v.y + dir[i][1]; if (dx <= 0 || dx > R || dy <= 0 || dy > C) { flag = v.t + 1; while (!J.empty())J.pop(); return; } if (map[dx][dy] != '#') { map[dx][dy] = '#'; J.push(f(dx, dy, v.t + 1)); } } } else return; } } int main() { int t; cin >> t; while (t--) { while (!J.empty())J.pop(); while (!F.empty())F.pop(); cin >> R >> C; for (int i = 1; i <= R; i++) { scanf("%s", map[i] + 1); for (int j = 1; j <= C; j++)if (map[i][j] == 'F') F.push(f(i, j, 0)), fired[i][j] = 1; else if (map[i][j] == 'J')J.push(f(i, j, 0)), map[i][j] = '#'; } flag = -1; T = 0; int tf = 0, tj = 0; while (!J.empty()) { spread(T); bfs(T); T++; if (flag > 0)break; } if (flag == -1)cout << "IMPOSSIBLE" << endl; else cout << flag << endl; } cin >> t; }
同学的想法是两次bfs,先bfs一次火的,把它抵达各个格子的时间填在一个表里,说明人在这个时间之后就不能走到这里了,把这个判断加到人的bfs里面即可
#define _CRT_SECURE_NO_WARNINGS #include#include #include #include #include #include <string.h> using namespace std; char map[1005][1005]; int vis[1005][1005]; int tf[1005][1005]; int n, m, ji, jj, fi, fj; struct Node { int i, j; Node(int i = 0, int j = 0) :i(i), j(j) {} }; queue q; int dir[4][2] = { { 1,0 },{ -1,0 },{ 0,1 },{ 0,-1 } }; void bfsf() { while (!q.empty()) { Node t = q.front(); q.pop(); for (int k = 0; k<4; k++) { int di = t.i + dir[k][0]; int dj = t.j + dir[k][1]; if (di<0 || di >= n || dj<0 || dj >= m || map[di][dj] == '#' || tf[di][dj] != -1) continue; q.push(Node(di, dj)); tf[di][dj] = tf[t.i][t.j] + 1; } } } int bfsj(int i, int j) { queue que; que.push(Node(i, j)); vis[i][j] = 0; while (!que.empty()) { Node t = que.front(); que.pop(); if (t.i == 0 || t.i == n - 1 || t.j == 0 || t.j == m - 1) return vis[t.i][t.j] + 1; for (int k = 0; k<4; k++) { int di = t.i + dir[k][0]; int dj = t.j + dir[k][1]; if (di<0 || di >= n || dj<0 || dj >= m || map[di][dj] == '#' || (vis[di][dj] != -1 || vis[t.i][t.j] + 1 >= tf[di][dj]&&tf[di][dj]>0)) continue; que.push(Node(di, dj)); vis[di][dj] = vis[t.i][t.j] + 1; } } return -1; } int main() { int t; scanf("%d", &t); while (t--) { memset(tf, -1, sizeof(tf)); scanf("%d%d", &n, &m); for (int i = 0; i ) { scanf("%s", map[i]); for (int j = 0; j ) { if (map[i][j] == 'J') ji = i, jj = j; if (map[i][j] == 'F') q.push(Node(i, j)), tf[i][j] = 0; } } bfsf(); /*for (int i = 0; i < n; i++) { for (int j = 0; j <= m; j++) cout << tf[i][j] << ' '; cout << endl; }*/ memset(vis, -1, sizeof(vis)); int ans = bfsj(ji, jj); if (ans == -1) printf("IMPOSSIBLE\n"); else printf("%d\n", ans); } return 0; }