LeetCode 2258. 逃离火灾:BFS

2023-11-10 15:01
文章标签 leetcode bfs 火灾 逃离 2258

本文主要是介绍LeetCode 2258. 逃离火灾:BFS,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【LetMeFly】2258.逃离火灾

力扣题目链接:https://leetcode.cn/problems/escape-the-spreading-fire/

给你一个下标从 0 开始大小为 m x n 的二维整数数组 grid ,它表示一个网格图。每个格子为下面 3 个值之一:

  • 0 表示草地。
  • 1 表示着火的格子。
  • 2 表示一座墙,你跟火都不能通过这个格子。

一开始你在最左上角的格子 (0, 0) ,你想要到达最右下角的安全屋格子 (m - 1, n - 1) 。每一分钟,你可以移动到 相邻 的草地格子。每次你移动 之后 ,着火的格子会扩散到所有不是墙的 相邻 格子。

请你返回你在初始位置可以停留的 最多 分钟数,且停留完这段时间后你还能安全到达安全屋。如果无法实现,请你返回 -1 。如果不管你在初始位置停留多久,你 总是 能到达安全屋,请你返回 109 。

注意,如果你到达安全屋后,火马上到了安全屋,这视为你能够安全到达安全屋。

如果两个格子有共同边,那么它们为 相邻 格子。

 

示例 1:

输入:grid = [[0,2,0,0,0,0,0],[0,0,0,2,2,1,0],[0,2,0,0,1,2,0],[0,0,2,2,2,0,2],[0,0,0,0,0,0,0]]
输出:3
解释:上图展示了你在初始位置停留 3 分钟后的情形。
你仍然可以安全到达安全屋。
停留超过 3 分钟会让你无法安全到达安全屋。

示例 2:

输入:grid = [[0,0,0,0],[0,1,2,0],[0,2,0,0]]
输出:-1
解释:上图展示了你马上开始朝安全屋移动的情形。
火会蔓延到你可以移动的所有格子,所以无法安全到达安全屋。
所以返回 -1 。

示例 3:

输入:grid = [[0,0,0],[2,2,0],[1,2,0]]
输出:1000000000
解释:上图展示了初始网格图。
注意,由于火被墙围了起来,所以无论如何你都能安全到达安全屋。
所以返回 109

 

提示:

  • m == grid.length
  • n == grid[i].length
  • 2 <= m, n <= 300
  • 4 <= m * n <= 2 * 104
  • grid[i][j] 是 0 ,1 或者 2 。
  • grid[0][0] == grid[m - 1][n - 1] == 0

方法一:二分 + BFS

首先以所有的🔥为起点开始广度优先搜索,这样我们就能得到“火焰燃烧图”(🔥燃烧到某个坐标所需耗时)。

接着可以二分“👱的开局等待时长”。假设开局等待时间为 t t t,那么就从时间 t t t开始对👱能到达的位置进行广度优先搜索。

在对👱的广搜过程中:

  • 若搜索到了“安全屋”的位置:若“👱的到达耗时小于等于🔥的到达耗时”,则表示👱能等待时间 t t t后再出发
  • 否则(非安全屋位置):若“👱的到达耗时小于🔥的到达耗时”,则表示人能到达该位置

以上,即可。

  • 时间复杂度 O ( m n log ⁡ m n ) O(mn\log mn) O(mnlogmn),其中 s i z e ( g r i d ) = m × n size(grid)=m\times n size(grid)=m×n
  • 空间复杂度 O ( m n ) O(mn) O(mn)

AC代码

C++
class Solution {
private:int m, n;int direction[4][2] = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};vector<vector<int>> fireTime;void debug(vector<vector<int>>& v) {for (auto& t : v) {for (auto& tt : t) {cout << tt << ' ';}cout << endl;}}void bfsFire(vector<vector<int>>& grid) {  // 计算火燃烧到每个位置时所需耗时并存入fireTimevector<vector<int>> graph = grid;fireTime = vector<vector<int>>(m, vector<int>(n, 1e9));queue<pair<int, int>> q;for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (graph[i][j] == 1) {q.push({i, j});fireTime[i][j] = 0;}}}while (q.size()) {auto [x, y] = q.front();q.pop();for (int d = 0; d < 4; d++) {int tx = x + direction[d][0];int ty = y + direction[d][1];if (tx >= 0 && tx < m && ty >= 0 && ty < n && !graph[tx][ty]) {graph[tx][ty] = 1;fireTime[tx][ty] = fireTime[x][y] + 1;q.push({tx, ty});}}}}bool check(vector<vector<int>>& grid, int t) {  // 其实是bfsPeoplevector<vector<int>> peopleTime(m, vector<int>(n, 0)), graph(grid);peopleTime[0][0] = t;queue<pair<int, int>> q;q.push({0, 0});graph[0][0] = 2;while (q.size()) {auto [x, y] = q.front();q.pop();for (int d = 0; d < 4; d++) {int tx = x + direction[d][0];int ty = y + direction[d][1];int toTime = peopleTime[x][y] + 1;if (tx >= 0 && tx < m && ty >= 0 && ty < n && !graph[tx][ty]) {graph[tx][ty] = 2;if (tx == m - 1 && ty == n - 1 && toTime <= fireTime[m - 1][n - 1]) {return true;}if (toTime < fireTime[tx][ty]) {peopleTime[tx][ty] = toTime;q.push({tx, ty});}}}}return false;}
public:int maximumMinutes(vector<vector<int>>& grid) {m = grid.size(), n = grid[0].size();bfsFire(grid);int l = 0, r = n * m;int ans = -1;while (l <= r) {int mid = l + (r - l) / 2;if (check(grid, mid)) {ans = mid;l = mid + 1;}else {r = mid - 1;}}return ans >= n * m ? 1e9 : ans;}
};
Python
# from typing import List
# from copy import deepcopyclass Solution:def __init__(self) -> None:self.direction = [[-1, 0], [1, 0], [0, -1], [0, 1]]def bfsFire(self, grid: List[List[int]]) -> None:fireTime = [[int(1e9)] * self.n for _ in range(self.m)]graph = deepcopy(grid)q = []for i in range(self.m):for j in range(self.n):if graph[i][j] == 1:q.append((i, j))fireTime[i][j] = 0while q:x, y = q[0]q = q[1:]for dx, dy in self.direction:tx, ty = x + dx, y + dyif tx >= 0 and tx < self.m and ty >= 0 and ty < self.n and not graph[tx][ty]:q.append((tx, ty))fireTime[tx][ty] = fireTime[x][y] + 1graph[tx][ty] = 1self.fireTime = fireTimedef check(self, grid: List[List[int]], t: int) -> bool:if t == 4:print(self.fireTime)peopleTime = [[0] * self.n for _ in range(self.m)]graph = deepcopy(grid)q = []q.append((0, 0))graph[0][0] = 2peopleTime[0][0] = twhile q:x, y = q[0]q = q[1:]thisTime = peopleTime[x][y] + 1for dx, dy in self.direction:tx, ty = x + dx, y + dyif tx >= 0 and tx < self.m and ty >= 0 and ty < self.n and not graph[tx][ty]:graph[tx][ty] = 2if tx == self.m - 1 and ty == self.n - 1 and thisTime <= self.fireTime[-1][-1]:return Trueif thisTime < self.fireTime[tx][ty]:peopleTime[tx][ty] = thisTimeq.append((tx, ty))return Falsedef maximumMinutes(self, grid: List[List[int]]) -> int:self.m, self.n = len(grid), len(grid[0])self.bfsFire(grid)l, r = 0, self.m * self.nans = -1while l <= r:mid = (l + r) // 2if self.check(grid, mid):ans = midl = mid + 1else:r = mid - 1return int(1e9) if ans >= self.m * self.n else ansif __name__ == '__main__':print(Solution().maximumMinutes([[0,2,0,0,0,0,0],[0,0,0,2,2,1,0],[0,2,0,0,1,2,0],[0,0,2,2,2,0,2],[0,0,0,0,0,0,0]]))"""[[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]]"""

方法二:数次BFS(无代码,可忽略)

其实这道题特殊的一点只有“安全屋”,只有安全屋这里🔥和👱可以同时到达。其他位置都必须保证👱比🔥严格地优先到达。

怎么到安全屋呢?要么从安全屋的左边,要么从安全屋的上面。因此先BFS一下得到🔥的“燃烧耗时图”,再按从 0 0 0时刻出发BFS👱。

最后判断一下安全屋及其左上两个位置👱🔥的到达时间,即可推断出👱在起点最多待多久。

2 15 > 2 × 1 0 4 2^{15}>2\times10^4 215>2×104,故方法一中也不会二分太多次。

同步发文于CSDN,原创不易,转载经作者同意后请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/134331955

这篇关于LeetCode 2258. 逃离火灾:BFS的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/383450

相关文章

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

hdu1254(嵌套bfs,两次bfs)

/*第一次做这种题感觉很有压力,思路还是有点混乱,总是wa,改了好多次才ac的思路:把箱子的移动当做第一层bfs,队列节点要用到当前箱子坐标(x,y),走的次数step,当前人的weizhi(man_x,man_y),要判断人能否将箱子推到某点时要嵌套第二层bfs(人的移动);代码如下:

poj 2195 bfs+有流量限制的最小费用流

题意: 给一张n * m(100 * 100)的图,图中” . " 代表空地, “ M ” 代表人, “ H ” 代表家。 现在,要你安排每个人从他所在的地方移动到家里,每移动一格的消耗是1,求最小的消耗。 人可以移动到家的那一格但是不进去。 解析: 先用bfs搞出每个M与每个H的距离。 然后就是网络流的建图过程了,先抽象出源点s和汇点t。 令源点与每个人相连,容量为1,费用为

leetcode-24Swap Nodes in Pairs

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode swapPairs(L

leetcode-23Merge k Sorted Lists

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode mergeKLists

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

POJ 3057 最大二分匹配+bfs + 二分

SampleInput35 5XXDXXX...XD...XX...DXXXXX5 12XXXXXXXXXXXXX..........DX.XXXXXXXXXXX..........XXXXXXXXXXXXX5 5XDXXXX.X.DXX.XXD.X.XXXXDXSampleOutput321impossible

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

【JavaScript】LeetCode:16-20

文章目录 16 无重复字符的最长字串17 找到字符串中所有字母异位词18 和为K的子数组19 滑动窗口最大值20 最小覆盖字串 16 无重复字符的最长字串 滑动窗口 + 哈希表这里用哈希集合Set()实现。左指针i,右指针j,从头遍历数组,若j指针指向的元素不在set中,则加入该元素,否则更新结果res,删除集合中i指针指向的元素,进入下一轮循环。 /*** @param