当前位置: 首页 > news >正文

每日算法刷题Day67:9.9:leetcode bfs10道题,用时2h30min

三. BFS基础

1.套路

1.求最短路等。要求边权都是 1(或者说都是同一个(重点)正数)
2.模板(单源最短路):

// 计算从start到各节点的最短路长度
// 如果节点不可达,则最短路长度为INT_MAX(涵盖了vis数组功能)
// 节点编号从0到n-1,边权均为1
vector<int> bfs(int n, vector<vector<int>>& edges, int start) {vector<vector<int>> g; // 邻接表for (auto& e : edges) {int x = e[0], y = e[1];g[x].push_back(y);g[y].push_back(x); // 无向图}vector<int> dis(n, INT_MAX); // 最短路长度queue<int> q;           //  队列模拟// 从start开始dis[start] = 0;q.push(start);while (!q.empty()) {int x = q.front();q.pop();// 遍历邻居for (auto& y : g[x]) {// 未访问则进队列,更新长度if (dis[y] < 0) {dis[y] = dis[x] + 1; // 按层q.push(y);}}}return dis;
}
2.题目描述
3.学习经验

1.要开dis数组,从而是按层数,不要用一个变量自增,这是来记录节点个数

1. 3243. 新增道路查询后的最短距离I(中等,学习)

3243. 新增道路查询后的最短距离 I - 力扣(LeetCode)

思想

1.给你一个整数 n 和一个二维整数数组 queries
有 n 个城市,编号从 0 到 n - 1。初始时,每个城市 i 都有一条单向道路通往城市 i + 1( 0 <= i < n - 1)。
queries[i] = [ui, vi] 表示新建一条从城市 ui 到城市 vi 的单向道路。每次查询后,你需要找到从城市 0 到城市 n - 1 的最短路径长度
返回一个数组 answer,对于范围 [0, queries.length - 1] 中的每个 ianswer[i] 是处理完 i + 1 个查询后,从城市 0 到城市 n - 1 的最短路径的_长度_。
2.查询一次添加一条路径,跑一次dfs,所以dfs写成函数,套用模版
3.最好的办法是dp

代码
class Solution {
public:vector<vector<int>> g;int bfs(int n) {vector<int> dis(n, -1);queue<int> que;dis[0] = 0;que.push(0);while (!que.empty()) {int x = que.front();que.pop();for (int& y : g[x]) {if (dis[y] == -1) {dis[y] = dis[x] + 1;if (y == n - 1)return dis[y];que.push(y);}}}return -1;}vector<int> shortestDistanceAfterQueries(int n,vector<vector<int>>& queries) {g.assign(n, {});vector<int> res;for (int i = 0; i + 1 < n; ++i) {g[i].push_back(i + 1);}for (auto& q : queries) {int x = q[0], y = q[1];g[x].push_back(y);res.push_back(bfs(n));}return res;}
};
2. 1311. 获取你好友已观看的视频(中等)

1311. 获取你好友已观看的视频 - 力扣(LeetCode)

思想

1.有 n 个人,每个人都有一个  0 到 n-1 的唯一 id 。
给你数组 watchedVideos  和 friends ,其中 watchedVideos[i]  和 friends[i] 分别表示 id = i 的人观看过的视频列表和他的好友列表。
Level 1 的视频包含所有你好友观看过的视频,level 2 的视频包含所有你好友的好友观看过的视频,以此类推。一般的,Level 为 k 的视频包含所有从你出发,最短距离为 k 的好友观看过的视频。
给定你的 id  和一个 level 值,请你找出所有指定 level 的视频,并将它们按观看频率升序返回。如果有频率相同的视频,请将它们按字母顺序从小到大排列。
2."并将它们按观看频率升序返回。如果有频率相同的视频,请将它们按字母顺序从小到大排列。"首先用map存储和更新,然后转移到vector,从而使用自定义排序,最好放入结果vector中

代码
typedef pair<string, int> PSI;
bool cmp(const PSI& a, const PSI& b) {if (a.second != b.second)return a.second < b.second;elsereturn a.first < b.first;
}
class Solution {
public:vector<string> watchedVideosByFriends(vector<vector<string>>& watchedVideos,vector<vector<int>>& friends, int id,int level) {map<string, int> mp;vector<string> res;int n = watchedVideos.size();vector<int> dis(n, -1);dis[id] = 0;queue<int> q;q.push(id);while (!q.empty()) {int x = q.front();q.pop();for (int& y : friends[x]) {if (dis[y] == -1) {dis[y] = dis[x] + 1;if (dis[y] == level) {for (auto s : watchedVideos[y]) {++mp[s];}}q.push(y);}}}vector<PSI> vec(mp.begin(), mp.end());sort(vec.begin(), vec.end(), cmp);for (auto& t : vec)res.push_back(t.first);return res;}
};
3. 1129. 颜色交替的最短路径(中等,学习)

1129. 颜色交替的最短路径 - 力扣(LeetCode)

思想

1.给定一个整数 n,即有向图中的节点数,其中节点标记为 0 到 n - 1。图中的每条边为红色或者蓝色,并且可能存在自环或平行边。
给定两个数组 redEdges 和 blueEdges,其中:

  • redEdges[i] = [ai, bi] 表示图中存在一条从节点 ai 到节点 bi 的红色有向边,
  • blueEdges[j] = [uj, vj] 表示图中存在一条从节点 uj 到节点 vj 的蓝色有向边。
    返回长度为 n 的数组 answer,其中 answer[X] 是从节点 0 到节点 X 的红色边和蓝色边交替出现的最短路径的长度。如果不存在这样的路径,那么 answer[x] = -1
    2.因为要求红蓝交错,所以存在一个节点遍历2次的情况,所以dis数组不能正常那样定义,而是也要分红蓝,各自有个dis,代表到当前节点最后一条边的颜色,所以这是第一维为颜色,第二维为最短距离的二维数组,同时结果取两者最小,所以初始化为INT_MAX.
    同时队列要记录上一条边的颜色,从而决定下一条边要枚举当前节点的红边还是蓝边,所以两条颜色各自建立一个邻接表
    最后,初始节点未定义上一条边颜色,所以要压入两个初始节点进入队列,分别为红色和蓝色,
代码
class Solution {
public:typedef pair<int, int> PII;vector<vector<int>> gRed;vector<vector<int>> gBlue;vector<int> shortestAlternatingPaths(int n, vector<vector<int>>& redEdges,vector<vector<int>>& blueEdges) {gRed.assign(n, {});gBlue.assign(n, {});for (auto& e : redEdges) {gRed[e[0]].push_back(e[1]);}for (auto& e : blueEdges) {gBlue[e[0]].push_back(e[1]);}vector<vector<int>> dis(2,vector<int>(n,INT_MAX)); // 第一维为颜色,代表到当前节点最后一条边什么颜色,0:红色,1:蓝色dis[0][0] = 0;dis[1][0] = 0;queue<PII> q;// 0前面任意颜色,所以两种都尝试q.push({0, 0});q.push({0, 1});while (!q.empty()) {auto t = q.front();q.pop();int x = t.first, pre = t.second;if (pre == 0) {for (int y : gBlue[x]) {if (dis[1][y] == INT_MAX) {dis[1][y] = dis[0][x] + 1;q.push({y, 1});}}} else {for (int y : gRed[x]) {if (dis[0][y] == INT_MAX) {dis[0][y] = dis[1][x] + 1;q.push({y, 0});}}}}vector<int> res(n, -1);for (int i = 0; i < n; ++i) {int d = min(dis[0][i], dis[1][i]);if (d != INT_MAX)res[i] = d;elseres[i] = -1;}return res;}
};

四. 网格图BFS

1.套路

1.适用于需要计算最短距离(最短路) 的题目。
2.模版:

class Solution {
public:int n, m;typedef pair<int, int> PII;vector<int> dx = {1, -1, 0, 0}, dy = {0, 0, 1, -1};bool inMap(int x, int y) { return 0 <= x && x < n && 0 <= y && y < m; }int nearestExit(vector<vector<char>>& maze, vector<int>& entrance) {n = maze.size(), m = maze[0].size();// 判断起始点:// return -1; // 起始点不满足条件// return 0; // 起始点即终点vector<vector<int>> dis(n, vector<int>(m, INT_MAX));queue<PII> q;int stx = entrance[0], sty = entrance[1];dis[stx][sty] = 0;q.push({stx, sty});while (!q.empty()) {auto t = q.front();q.pop();int x = t.first, y = t.second;for (int i = 0; i < 4; ++i) {int nx = x + dx[i], ny = y + dy[i];if (!inMap(nx, ny) || maze[nx][ny] == '+')continue;if (dis[nx][ny] == INT_MAX) {dis[nx][ny] = dis[x][y] + 1;if (nx == 0 || nx == n - 1 || ny == 0 || ny == m - 1) {return dis[nx][ny];}q.push({nx, ny});}}}return -1;}
};

3.多源最短路模版:

class Solution {
public:int n;typedef pair<int, int> PII;vector<int> dx = {1, -1, 0, 0}, dy = {0, 0, 1, -1};bool inMap(int x, int y) { return 0 <= x && x < n && 0 <= y && y < n; }int maxDistance(vector<vector<int>>& grid) {n = grid.size();queue<PII> q;vector<vector<int>> dis(n, vector<int>(n, INT_MAX));for (int i = 0; i < n; ++i) {for (int j = 0; j < n; ++j) {// 陆地入队列if (grid[i][j] == 1) {q.push({i, j});dis[i][j] = 0;}}}// 全是陆地或海洋if (q.size() == 0 || q.size() == n * n)return -1;int res = -1;while (!q.empty()) {auto t = q.front();q.pop();int x = t.first, y = t.second;for (int i = 0; i < 4; ++i) {int nx = x + dx[i], ny = y + dy[i];if (!inMap(nx, ny) || grid[nx][ny] == 1)continue;if (dis[nx][ny] == INT_MAX) {dis[nx][ny] = dis[x][y] + 1;res = max(res, dis[nx][ny]);q.push({nx, ny});}}}return res;}
};
2.题目描述
3.学习经验

1.与三.BFS基础不同点在于,BFS基础是枚举邻接表的邻居,而网格图BFS是枚举四个方向的邻居
2.模版里判断不了起始点即终点的情况,要单独判断
3.多源最短路问题不再是找一个点到某个满足条件的点的最短距离,而是找多个相同点到各自某个满足条件的点的最短距离。所以要反过来,将所有满足条件的点当做多个源点,向外扩散,从而告诉待求点当前扩散的层数,即最短距离。将多个源头进入队列,整体出队列就相当于所有源头向外拓展一次,且BFS得到的最短距离就是曼哈顿距离

1. 1926. 迷宫中离入口最近的出口(中等)

1926. 迷宫中离入口最近的出口 - 力扣(LeetCode)

思想

1.给你一个 m x n 的迷宫矩阵 maze (下标从 0 开始),矩阵中有空格子(用 '.' 表示)和墙(用 '+' 表示)。同时给你迷宫的入口 entrance ,用 entrance = [entrancerow, entrancecol] 表示你一开始所在格子的行和列。
每一步操作,你可以往  或者  移动一个格子。你不能进入墙所在的格子,你也不能离开迷宫。你的目标是找到离 entrance 最近 的出口。出口 的含义是 maze 边界 上的 空格子entrance 格子 不算 出口。
请你返回从 entrance 到最近出口的最短路径的 步数 ,如果不存在这样的路径,请你返回 -1 。
2.求最短路径,想到bfs,用dis数组,网格图中枚举四个方向

代码
class Solution {
public:int n, m;typedef pair<int, int> PII;vector<int> dx = {1, -1, 0, 0}, dy = {0, 0, 1, -1};bool inMap(int x, int y) { return 0 <= x && x < n && 0 <= y && y < m; }int nearestExit(vector<vector<char>>& maze, vector<int>& entrance) {n = maze.size(), m = maze[0].size();vector<vector<int>> dis(n, vector<int>(m, -1));queue<PII> q;int stx = entrance[0], sty = entrance[1];dis[stx][sty] = 0;q.push({stx, sty});while (!q.empty()) {auto t = q.front();q.pop();int x = t.first, y = t.second;for (int i = 0; i < 4; ++i) {int nx = x + dx[i], ny = y + dy[i];if (!inMap(nx, ny) || maze[nx][ny] == '+')continue;if (dis[nx][ny] == -1) {dis[nx][ny] = dis[x][y] + 1;if ((nx != stx || ny != sty) &&(nx == 0 || nx == n - 1 || ny == 0 || ny == m - 1)) {return dis[nx][ny];}q.push({nx, ny});}}}return -1;}
};
2. 1091. 二进制矩阵中的最短路径(中等)

1091. 二进制矩阵中的最短路径 - 力扣(LeetCode)

思想

1.给你一个 n x n 的二进制矩阵 grid 中,返回矩阵中最短 畅通路径 的长度。如果不存在这样的路径,返回 -1 。
二进制矩阵中的 畅通路径 是一条从 左上角 单元格(即,(0, 0))到 右下角 单元格(即,(n - 1, n - 1))的路径,该路径同时满足下述要求:

  • 路径途经的所有单元格的值都是 0 。
  • 路径中所有相邻的单元格应当在 8 个方向之一 上连通(即,相邻两单元之间彼此不同且共享一条边或者一个角)。
    畅通路径的长度 是该路径途经的单元格总数。
    2.起始点要多考虑一下:
    (1)起始点为1,直接返回-1
    (2)起始点即终点,即n=1,返回1
代码
class Solution {
public:int n;typedef pair<int, int> PII;vector<int> dx = {1, -1, 0, 0, 1, -1, 1, -1},dy = {0, 0, 1, -1, 1, 1, -1, -1};bool inMap(int x, int y) { return 0 <= x && x < n && 0 <= y && y < n; }int shortestPathBinaryMatrix(vector<vector<int>>& grid) {if (grid[0][0] != 0)return -1;n = grid.size();if(n==1)    return 1;vector<vector<int>> dis(n, vector<int>(n, -1));queue<PII> q;dis[0][0] = 1;q.push({0, 0});while (!q.empty()) {auto t = q.front();q.pop();int x = t.first, y = t.second;for (int i = 0; i < 8; ++i) {int nx = x + dx[i], ny = y + dy[i];if (!inMap(nx, ny) || grid[nx][ny] != 0)continue;if (dis[nx][ny] == -1) {dis[nx][ny] = dis[x][y] + 1;if (nx == n - 1 && ny == n - 1)return dis[nx][ny];q.push({nx, ny});}}}return -1;}
};
3. 1162. 地图分析(中等,学习多源最短路径)

1162. 地图分析 - 力扣(LeetCode)

思想

1.你现在手里有一份大小为 n x n 的 网格 grid,上面的每个 单元格 都用 0 和 1 标记好了。其中 0 代表海洋,1 代表陆地。
请你找出一个海洋单元格,这个海洋单元格到离它最近的陆地单元格的距离是最大的,并返回该距离。如果网格上只有陆地或者海洋,请返回 -1
我们这里说的距离是「曼哈顿距离」( Manhattan Distance):(x0, y0) 和 (x1, y1) 这两个单元格之间的距离是 |x0 - x1| + |y0 - y1| 。
2.这题是要求某个海洋单元格到离它最近的陆地单元格的距离的最大值,因为某个海洋单元格未知,而陆地单元格已知,所以转变题意为所有陆地单元格到离各自最近的海洋单元格的距离的最大值,即有多个源头,为多源最短路问题。因为BFS是层级的,所以可以先将所有陆地进入队列,然后一次整体出队列就相当于所有陆地向四周拓展一格,最终遍历到的海洋格子就是最大值,如下图所示
![[地图分析.png]]

代码
class Solution {
public:int n;typedef pair<int, int> PII;vector<int> dx = {1, -1, 0, 0}, dy = {0, 0, 1, -1};bool inMap(int x, int y) { return 0 <= x && x < n && 0 <= y && y < n; }int maxDistance(vector<vector<int>>& grid) {n = grid.size();queue<PII> q;vector<vector<int>> dis(n, vector<int>(n, -1));for (int i = 0; i < n; ++i) {for (int j = 0; j < n; ++j) {// 陆地入队列if (grid[i][j] == 1) {q.push({i, j});dis[i][j] = 0;}}}// 全是陆地或海洋if (q.size() == 0 || q.size() == n * n)return -1;int res = -1;while (!q.empty()) {auto t = q.front();q.pop();int x = t.first, y = t.second;for (int i = 0; i < 4; ++i) {int nx = x + dx[i], ny = y + dy[i];if (!inMap(nx, ny) || grid[nx][ny] == 1)continue;if (dis[nx][ny] == -1) {dis[nx][ny] = dis[x][y] + 1;res = max(res, dis[nx][ny]);q.push({nx, ny});}}}return res;}
};
4. 542. 01矩阵(中等)

542. 01 矩阵 - 力扣(LeetCode)

思想

1.给定一个由 0 和 1 组成的矩阵 mat ,请输出一个大小相同的矩阵,其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。
两个相邻元素间的距离为 1 。
2.与[[十.图论算法-基础遍历#3. 1162. 地图分析(中等,学习)]]一模一样,找每个1到各自最近的0的最短距离,即多源最短路径距离,所以将所有0入队列,向四周扩散,告诉1已经扩散的层数,即距离

代码
class Solution {
public:int n, m;typedef pair<int, int> PII;bool inMap(int x, int y) { return 0 <= x && x < n && 0 <= y && y < m; }vector<int> dx = {1, -1, 0, 0}, dy = {0, 0, 1, -1};vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {n = mat.size(), m = mat[0].size();vector<vector<int>> dis(n, vector<int>(m, -1));queue<PII> q;for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {if (mat[i][j] == 0) {dis[i][j] = 0;q.push({i, j});}}}while (!q.empty()) {auto t = q.front();q.pop();int x = t.first, y = t.second;for (int i = 0; i < 4; ++i) {int nx = x + dx[i], ny = y + dy[i];if (!inMap(nx, ny) || mat[nx][ny] == 0)continue;if (dis[nx][ny] == -1) {dis[nx][ny] = dis[x][y] + 1;q.push({nx, ny});}}}return dis;}
};
5. 994. 腐烂的橘子(中等)

994. 腐烂的橘子 - 力扣(LeetCode)

思想

1.在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一:

  • 值 0 代表空单元格;
  • 值 1 代表新鲜橘子;
  • 值 2 代表腐烂的橘子。
    每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。
    返回 直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1 。
    2.题目意思为每分钟,所有腐烂橘子向四周扩散一层,即多源最短路问题,分钟即最短距离
代码
class Solution {
public:int n, m;typedef long long ll;typedef pair<int, int> PII;vector<int> dx = {1, -1, 0, 0}, dy = {0, 0, 1, -1};bool inMap(int x, int y) { return 0 <= x && x < n && 0 <= y && y < m; }int orangesRotting(vector<vector<int>>& grid) {n = grid.size(), m = grid[0].size();ll cnt = 0;vector<vector<int>> dis(n, vector<int>(m, -1));queue<PII> q;for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {if (grid[i][j] == 1) {++cnt;} else if (grid[i][j] == 2) {dis[i][j] = 0;q.push({i, j});}}}if (cnt == 0)return 0;while (!q.empty()) {auto t = q.front();q.pop();int x = t.first, y = t.second;for (int i = 0; i < 4; ++i) {int nx = x + dx[i], ny = y + dy[i];if (!inMap(nx, ny) || grid[nx][ny] != 1)continue;if (dis[nx][ny] == -1) {dis[nx][ny] = dis[x][y] + 1;--cnt;if (cnt == 0)return dis[nx][ny];q.push({nx, ny});}}}return -1;}
};
6. 1765. 地图中的最高点(中等)

1765. 地图中的最高点 - 力扣(LeetCode)

思想

1.给你一个大小为 m x n 的整数矩阵 isWater ,它代表了一个由 陆地 和 水域 单元格组成的地图。

  • 如果 isWater[i][j] == 0 ,格子 (i, j) 是一个 陆地 格子。
  • 如果 isWater[i][j] == 1 ,格子 (i, j) 是一个 水域 格子。
    你需要按照如下规则给每个单元格安排高度:
  • 每个格子的高度都必须是非负的。
  • 如果一个格子是 水域 ,那么它的高度必须为 0 。
  • 任意相邻的格子高度差 至多 为 1 。当两个格子在正东、南、西、北方向上相互紧挨着,就称它们为相邻的格子。(也就是说它们有一条公共边)
    找到一种安排高度的方案,使得矩阵中的最高高度值 最大 。
    请你返回一个大小为 m x n 的整数矩阵 height ,其中 height[i][j] 是格子 (i, j) 的高度。如果有多种解法,请返回 任意一个 。
    2.依然是多源最短路问题,即所有源头水域向外扩散层数,保证相邻高度(层级)差至多为1
代码
class Solution {
public:int n, m;typedef pair<int, int> PII;vector<int> dx = {1, -1, 0, 0}, dy = {0, 0, 1, -1};bool inMap(int x, int y) { return 0 <= x && x < n && 0 <= y && y < m; }vector<vector<int>> highestPeak(vector<vector<int>>& isWater) {n = isWater.size(), m = isWater[0].size();vector<vector<int>> dis(n, vector<int>(m, -1));queue<PII> q;for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {if (isWater[i][j] == 1) {dis[i][j] = 0;q.push({i, j});}}}while (!q.empty()) {auto t = q.front();q.pop();int x = t.first, y = t.second;for (int i = 0; i < 4; ++i) {int nx = x + dx[i], ny = y + dy[i];if (!inMap(nx, ny) || isWater[nx][ny] == 1)continue;if (dis[nx][ny] == -1) {dis[nx][ny] = dis[x][y] + 1;q.push({nx, ny});}}}return dis;}
};

五.网格图 0-1 BFS(边权0和1对Dijkstra的优化)

1.套路

1.边权只有 0 和 1 的题目,也可以用 BFS 做。
2.网格图点的值就是边权,把边权当做代价cost,即求起点到终点的最小代价,是Dijkstra算法,但因为边权只有0和1,所以用0-1BFS来优化Dijkstra,双端队列队首入0,队尾入1,保证每次队首都是边权(代价)最小的。
3.代码

class Solution {
public:int n, m;typedef pair<int, int> PII;vector<int> dx = {1, -1, 0, 0}, dy = {0, 0, 1, -1};bool inMap(int x, int y) { return 0 <= x && x < n && 0 <= y && y < m; }bool findSafeWalk(vector<vector<int>>& grid, int health) {n = grid.size(), m = grid[0].size();vector<vector<int>> dis(n, vector<int>(m, INT_MAX));dis[0][0] = grid[0][0];deque<PII> deq;deq.push_front({0, 0});while (!deq.empty()) {auto t = deq.front();deq.pop_front();int x = t.first, y = t.second;for (int i = 0; i < 4; ++i) {int nx = x + dx[i], ny = y + dy[i];if (!inMap(nx, ny))continue;int cost = grid[nx][ny]; // 边权/代价if (dis[x][y] + cost < dis[nx][ny]) {dis[nx][ny] = dis[x][y] + cost;// 提前终点结束if (nx == n - 1 && ny == m - 1 && dis[nx][ny] < health)return true;// 双端队列分情况if (cost == 0)deq.push_front({nx, ny});elsedeq.push_back({nx, ny});}}}return dis[n - 1][m - 1] < health;}
};
2.题目描述
3.学习经验
1. 3286. 穿越网格图的安全路径(中等,学习)

3286. 穿越网格图的安全路径 - 力扣(LeetCode)

思想

1.给你一个 m x n 的二进制矩形 grid 和一个整数 health 表示你的健康值。
你开始于矩形的左上角 (0, 0) ,你的目标是矩形的右下角 (m - 1, n - 1) 。
你可以在矩形中往上下左右相邻格子移动,但前提是你的健康值始终是 正数 。
对于格子 (i, j) ,如果 grid[i][j] = 1 ,那么这个格子视为 不安全 的,会使你的健康值减少 1 。
如果你可以到达最终的格子,请你返回 true ,否则返回 false 。
注意 ,当你在最终格子的时候,你的健康值也必须为 正数 。
2.能想到的是dfs+回溯(因为一个格子经过多次时的health不同,结果不同,需多次遍历一个格子)+记忆化剪枝(一个各自三个特征:x,y,health)
3.优化:
判断有没有一条路径,即从起点到终点的最小代价路是否小于health,所以是最短路问题。因为边权是0和1,所以可以用BFS。

代码

1.回溯+记忆化
(1)更新vis在终止条件和剪枝后判断
(2)回溯vis在return前回溯
(3)记忆化剪枝在终止条件后,更新vis前
(4)更新记忆化在return之前

class Solution {
public:int n, m;vector<vector<bool>> vis;vector<int> dx = {1, -1, 0, 0}, dy = {0, 0, 1, -1};bool inMap(int x, int y) { return 0 <= x && x < n && 0 <= y && y < m; }vector<vector<vector<int>>> dp; // -1:未访问,0:不可行,1:可行bool dfs(int x, int y, vector<vector<int>>& grid, int health) {if (grid[x][y] == 1) {--health;if (health <= 0)return false;}if (x == n - 1 && y == m - 1)return true;if (dp[x][y][health] != -1)return dp[x][y][health];vis[x][y] = true;for (int i = 0; i < 4; ++i) {int nx = x + dx[i], ny = y + dy[i];if (!inMap(nx, ny) || vis[nx][ny])continue;if (dfs(nx, ny, grid, health)) {vis[x][y] = false;dp[x][y][health] = 1;return true;}}vis[x][y] = false;dp[x][y][health] = 0;return false;}bool findSafeWalk(vector<vector<int>>& grid, int health) {n = grid.size(), m = grid[0].size();vis.assign(n, vector<bool>(m, false));dp.assign(n, vector<vector<int>>(m, vector<int>(health + 1, -1)));return dfs(0, 0, grid, health);}
};

2.0-1BFS

class Solution {
public:int n, m;typedef pair<int, int> PII;vector<int> dx = {1, -1, 0, 0}, dy = {0, 0, 1, -1};bool inMap(int x, int y) { return 0 <= x && x < n && 0 <= y && y < m; }bool findSafeWalk(vector<vector<int>>& grid, int health) {n = grid.size(), m = grid[0].size();vector<vector<int>> dis(n, vector<int>(m, INT_MAX));dis[0][0] = grid[0][0];deque<PII> deq;deq.push_front({0, 0});while (!deq.empty()) {auto t = deq.front();deq.pop_front();int x = t.first, y = t.second;for (int i = 0; i < 4; ++i) {int nx = x + dx[i], ny = y + dy[i];if (!inMap(nx, ny))continue;int cost = grid[nx][ny];if (dis[x][y] + cost < dis[nx][ny]) {dis[nx][ny] = dis[x][y] + cost;if (nx == n - 1 && ny == m - 1 && dis[nx][ny] < health)return true;if (cost == 0)deq.push_front({nx, ny});elsedeq.push_back({nx, ny});}}}return dis[n - 1][m - 1] < health;}
};

文章转载自:

http://BmACI2KL.rghkg.cn
http://FTMiQZxh.rghkg.cn
http://5OR1EMuo.rghkg.cn
http://qPXb97il.rghkg.cn
http://CkUPy072.rghkg.cn
http://lOwoKjZ8.rghkg.cn
http://B8SpLfL0.rghkg.cn
http://LWKZ5m4d.rghkg.cn
http://gc6YKl3F.rghkg.cn
http://cqaYwmvY.rghkg.cn
http://XQ5Wn0Lj.rghkg.cn
http://McqH5sy3.rghkg.cn
http://3ZSbBxcl.rghkg.cn
http://DPmeX4Ao.rghkg.cn
http://7XF06TMY.rghkg.cn
http://adS2bnl9.rghkg.cn
http://Ziu1qQ3u.rghkg.cn
http://XwqChi6T.rghkg.cn
http://87pOXwNJ.rghkg.cn
http://uqmVqCH0.rghkg.cn
http://62UUPn6l.rghkg.cn
http://Y8imk565.rghkg.cn
http://GAQP6XNH.rghkg.cn
http://PjL0BzPB.rghkg.cn
http://Mb2sc5iA.rghkg.cn
http://suqHce9Q.rghkg.cn
http://H27JPYaT.rghkg.cn
http://DxsQTwbs.rghkg.cn
http://UJbPzLaT.rghkg.cn
http://VIdFEzZV.rghkg.cn
http://www.dtcms.com/a/375387.html

相关文章:

  • PCL 基于法向量进行颜色插值赋色
  • 四数之和
  • MySql案例详解之事务
  • golang 语言核心
  • 【项目】在AUTODL上使用langchain实现《红楼梦》知识图谱和RAG混合检索(二)RAG部分
  • 安卓学习 之 贞布局FrameLayout
  • 【ISP】Charlite工具实操
  • IntelliJ IDEA断点调试全攻略
  • OceanBase存储过程基本使用
  • 使用 OBD 交互式部署单点OceanBase数据库
  • 内存管理这一块
  • 【深度学习新浪潮】什么是具身智能?
  • Linux tc 常用命令总结(网卡限速、延迟、丢包与整形)
  • Windows 命令行:路径末端的反斜杠
  • Shell脚本编程基本认识
  • Redis 面试
  • 大学地理信息科学该如何学习才能好就业
  • 浅谈“SVMSPro视频切片”技术应用场景
  • OpenHarmony多模输入子系统全链路剖析:从HCS配置到HDI芯片驱动源码深度解读
  • 1. linux 下qt 应用开机自启,需要sudo时
  • QML中的Popup
  • Cursor Pro试用
  • shell介绍
  • vla 开源最强的模型是哪一个
  • FreeRTOS任务切换详解
  • 面试不会问题
  • 享元模式,用Qt/C++绘制森林
  • GO RPC 教学文档
  • Atlantis Word Processor:全方位的文字处理专家
  • [iOS] 单例模式的深究