leetcode_2258 逃离火灾

1. 题意

给定一个二维矩阵,人的位置在 ( 0 , 0 ) (0,0) (0,0), 需要到达右下角的安全屋 ( r o w − 1 , c o l − 1 ) (row - 1, col - 1) (row1,col1)。给定 k k k个火的位置。火每秒钟会向旁边的一个格子蔓延。问最多等待多少秒还可以不被火烧的情况下,安全到达右下角。

逃离火灾

2. 题解

思路:BFS遍历得到火苗到达各个位置的时间。人根据当前时间判断是否会被火烧到。

2.1 BFS + 二分

由于答案在一定范围内,我们可以进行二分尝试。

  • 代码
class Solution {
public:
    struct pos {
        pos(int _x,int _y):x(_x),y(_y)
        {}
        int x,y;
    };
    static constexpr int INF = 0x3f3f3f3f;
    int dir[4][2] = 
    {
        {0,1},
        {0,-1},
        {1, 0},
        {-1, 0}
    };
    bool check(const vector<vector<int>> &grid, 
               vector<vector<int>> &fireAt, 
               pos cur) 
    {
        int r = grid.size();
        int c = grid[0].size();

        if ( cur.x >= r || cur.x < 0)
            return false;
        if ( cur.y >= c || cur.y < 0)
            return false;

        if ( grid[cur.x][cur.y] == 2)
            return false;
        if (fireAt[cur.x][cur.y] != INF)
            return false;


        return true;
    }
    void calDis(queue<pos> &q, vector<vector<int>> const &grid,
                vector<vector<int>> &disArr)
    {

        while (!q.empty()) {
            pos cur = q.front();
            q.pop();

            for ( int i = 0;i < 4; ++i) {
                pos nxt(cur.x + dir[i][0], cur.y + dir[i][1]);
                if ( check(grid,disArr, nxt)) {
                    disArr[nxt.x][nxt.y] = disArr[cur.x][cur.y] + 1;
                    q.push(nxt); 
                }
            }

        }
    }


    void calFireTime(queue<pos> &q,
                    const vector<vector<int>>&grid, 
                     vector<vector<int>>&fireAt){
        int r = grid.size();
        int c = grid[0].size();
        

        for (int i = 0; i < r; ++i) {
            for ( int j = 0; j < c; ++j) {
                if (grid[i][j] == 1) {
                    q.push({i,j});
                    fireAt[i][j] = 0;
                }
            }
        }
        calDis(q, grid, fireAt);                 
    }
    void calReachTime(queue<pos> &q,
                      const vector<vector<int>> &grid,
                     vector<vector<int>> &reachAt)
    {
        reachAt[0][0] = 0;
        q.push({0,0});

        calDis(q, grid, reachAt);
    }

    bool check_safe(pos pre, pos cur,int stayTime,
                     const vector<vector<int>> &fireAt,
                     const vector<vector<int>> &reachAt)
    {
        int r = fireAt.size();
        int c = fireAt[0].size();

        if ( cur.x < 0 || cur.x >= r)
            return false;
        if ( cur.y < 0 || cur.y >= c)
            return false;
        if (reachAt[cur.x][cur.y] == INF)
            return false;
        if (reachAt[pre.x][pre.y] >= reachAt[cur.x][cur.y])
            return false;

        if (stayTime + reachAt[cur.x][cur.y] >= fireAt[cur.x][cur.y])
            return false;

        return true;
    }

    bool canEscape(int stayTime, 
                   const vector<vector<int>> &fireAt,
                   const vector<vector<int>> &reachAt)
    {

        if ( stayTime >= fireAt[0][0] )
            return false;

        int r = fireAt.size();
        int c = fireAt[0].size();

        queue<pos> q;
        q.push({0, 0});

        while (!q.empty()) {
            pos cur = q.front();
            q.pop();

            for ( int i = 0; i < 4; ++i ) {
                pos nxt(cur.x + dir[i][0], cur.y + dir[i][1] );
                if ( nxt.x == r - 1 && nxt.y == c - 1 && 
                     (stayTime + reachAt[r - 1][c - 1]) <= fireAt[r - 1][c - 1])
                    return true;
                if ( check_safe(cur, nxt, stayTime, fireAt, reachAt)) {
                    q.push(nxt);
                }
            }
        }
        
        return false;
    }
    void debug_output(const vector<vector<int>> &arrs) {
        for ( auto &arr: arrs) {
            for (int v: arr) {
                cout << " ";
                if (v == INF)
                    cout << "#";
                else
                    cout << v;
            }
            cout << endl;
        }
    }

    int maximumMinutes(vector<vector<int>>& grid) {
        
        int r = grid.size();
        int c = grid[0].size();

        vector<vector<int>> fireAt(r,  vector<int>(c, INF));
        vector<vector<int>> reachAt(r, vector<int>(c, INF));

        queue<pos> q;

        calReachTime(q, grid, reachAt);
        calFireTime(q, grid, fireAt);
        

        // debug_output(reachAt);
        // debug_output(fireAt);

        if ( reachAt[r - 1][c - 1] == INF)
            return -1;

        int lo = 0;
        int hi = 1e9;

        while ( lo <= hi) {
            int mid = (lo + hi)/2;
            // if ( mid < 10)
            //     cout << lo << " " << hi << endl;
            if ( canEscape(mid, fireAt, reachAt) ) {
                lo = mid + 1;
            }
            else {
                hi = mid - 1;
            }
        }

        

        return hi;
    }
};

//  0 # 4 5 6 7 8
//  1 2 3 # # 8 9
//  2 # 4 5 6 # 10
//  3 4 # # # 10 #
//  4 5 6 7 8 9 10

//  6 # 4 3 2 1 2
//  5 4 3 # # 0 1
//  6 # 2 1 0 # 2
//  7 8 # # # 14 #
//  8 9 10 11 12 13 14


2.2 BFS + 直接计算

直接算出人和火到达各个点的时间。
分类讨论

由于可以跟火同时到达安全屋,所以我们需要讨论是否能取到边界值。
直接根据能否比火先到安全屋的左方块或者上方块判断,能否取到。


class Solution {
public:
    struct pos {
        pos(int _x,int _y):x(_x),y(_y)
        {}
        int x,y;
    };
    static constexpr int INF = 0x3f3f3f3f;
    int dir[4][2] = 
    {
        {0,1},
        {0,-1},
        {1, 0},
        {-1, 0}
    };
    bool check(const vector<vector<int>> &grid, 
               vector<vector<int>> &fireAt, 
               pos cur) 
    {
        int r = grid.size();
        int c = grid[0].size();

        if ( cur.x >= r || cur.x < 0)
            return false;
        if ( cur.y >= c || cur.y < 0)
            return false;

        if ( grid[cur.x][cur.y] == 2)
            return false;
        if (fireAt[cur.x][cur.y] != INF)
            return false;


        return true;
    }
    void calDis(queue<pos> &q, vector<vector<int>> const &grid,
                vector<vector<int>> &disArr)
    {

        while (!q.empty()) {
            pos cur = q.front();
            q.pop();

            for ( int i = 0;i < 4; ++i) {
                pos nxt(cur.x + dir[i][0], cur.y + dir[i][1]);
                if ( check(grid,disArr, nxt)) {
                    disArr[nxt.x][nxt.y] = disArr[cur.x][cur.y] + 1;
                    q.push(nxt); 
                }
            }

        }
    }


    void calFireTime(queue<pos> &q,
                    const vector<vector<int>>&grid, 
                     vector<vector<int>>&fireAt){
        int r = grid.size();
        int c = grid[0].size();
        

        for (int i = 0; i < r; ++i) {
            for ( int j = 0; j < c; ++j) {
                if (grid[i][j] == 1) {
                    q.push({i,j});
                    fireAt[i][j] = 0;
                }
            }
        }
        calDis(q, grid, fireAt);                 
    }
    void calReachTime(queue<pos> &q,
                      const vector<vector<int>> &grid,
                     vector<vector<int>> &reachAt)
    {
        reachAt[0][0] = 0;
        q.push({0,0});

        calDis(q, grid, reachAt);
    }

    bool check_safe(pos pre, pos cur,int stayTime,
                     const vector<vector<int>> &fireAt,
                     const vector<vector<int>> &reachAt)
    {
        int r = fireAt.size();
        int c = fireAt[0].size();

        if ( cur.x < 0 || cur.x >= r)
            return false;
        if ( cur.y < 0 || cur.y >= c)
            return false;
        if (reachAt[cur.x][cur.y] == INF)
            return false;
        if (reachAt[pre.x][pre.y] >= reachAt[cur.x][cur.y])
            return false;

        if (stayTime + reachAt[cur.x][cur.y] >= fireAt[cur.x][cur.y])
            return false;

        return true;
    }

    bool canEscape(int stayTime, 
                   const vector<vector<int>> &fireAt,
                   const vector<vector<int>> &reachAt)
    {

        if ( stayTime >= fireAt[0][0] )
            return false;

        int r = fireAt.size();
        int c = fireAt[0].size();

        queue<pos> q;
        q.push({0, 0});

        while (!q.empty()) {
            pos cur = q.front();
            q.pop();

            for ( int i = 0; i < 4; ++i ) {
                pos nxt(cur.x + dir[i][0], cur.y + dir[i][1] );
                if ( nxt.x == r - 1 && nxt.y == c - 1 && 
                     (stayTime + reachAt[r - 1][c - 1]) <= fireAt[r - 1][c - 1])
                    return true;
                if ( check_safe(cur, nxt, stayTime, fireAt, reachAt)) {
                    q.push(nxt);
                }
            }
        }
        
        return false;
    }
    void debug_output(const vector<vector<int>> &arrs) {
        for ( auto &arr: arrs) {
            for (int v: arr) {
                cout << " ";
                if (v == INF)
                    cout << "#";
                else
                    cout << v;
            }
            cout << endl;
        }
    }

    int maximumMinutes(vector<vector<int>>& grid) {
        
        int r = grid.size();
        int c = grid[0].size();

        vector<vector<int>> fireAt(r,  vector<int>(c, INF));
        vector<vector<int>> reachAt(r, vector<int>(c, INF));

        queue<pos> q;

        calReachTime(q, grid, reachAt);
        calFireTime(q, grid, fireAt);
        

        // debug_output(reachAt);
        // debug_output(fireAt);

        if ( reachAt[r - 1][c - 1] == INF)
            return -1;

        int lo = 0;
        int hi = 1e9;

        while ( lo <= hi) {
            int mid = (lo + hi)/2;
            // if ( mid < 10)
            //     cout << lo << " " << hi << endl;
            if ( canEscape(mid, fireAt, reachAt) ) {
                lo = mid + 1;
            }
            else {
                hi = mid - 1;
            }
        }

        

        return hi;
    }
};


Ref

03xf

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值