UVA - 11624 Fire! bfs 地图与人一步一步先后搜/搜一次打表好了再搜一次

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<cstdio>  
#include<algorithm>  
#include<iostream>
#include<string>
#include<vector>
#include<string.h>
#include<queue>
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 > 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 <iostream>
        #include <cstdio>
        #include <algorithm>
        #include <queue>
        #include <vector>
        #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<Node>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<Node>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<n; i++) {
                    scanf("%s", map[i]);
                    for (int j = 0; j<m; 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;
        }

 

posted @ 2018-03-21 13:47  SuuTTT  阅读(173)  评论(0编辑  收藏  举报