3286、[中等] 穿越网格图的安全路径
1、题目描述
给你一个 m x n
的二进制矩形 grid
和一个整数 health
表示你的健康值。你开始于矩形的左上角 (0, 0)
,你的目标是矩形的右下角 (m - 1, n - 1)
。你可以在矩形中往上下左右相邻格子移动,但前提是你的健康值始终是 正数 。
对于格子 (i, j)
,如果 grid[i][j] = 1
,那么这个格子视为 不安全 的,会使你的健康值减少 1 。如果你可以到达最终的格子,请你返回 true
,否则返回 false
。
注意 ,当你在最终格子的时候,你的健康值也必须为 正数 。
2、解题思路
这个问题可以通过图的最短路径算法来解决。我们需要使用一个动态规划 (DP) 方法来记录从起点到每个位置所需的最小健康值。在这个问题中,我们可以将 DP 结合 DFS 来实现。
详细步骤
- 初始化 :
- 创建一个二维 DP 数组
dp
,用于记录从起点(0, 0)
到每个位置(i, j)
所需的最小健康值。 - 将 DP 数组初始化为
INT_MAX
(一个非常大的数),表示未访问的状态。起点(0, 0)
的 DP 值初始化为grid[0][0]
,即起点的健康消耗值。
- 创建一个二维 DP 数组
- DFS 遍历 :
- 使用 DFS 遍历矩阵中的每个位置
(i, j)
。 - 对于每个位置
(i, j)
,尝试向四个方向移动,检查是否可以到达邻居格子,并更新其 DP 值。 - 如果到达新位置的最小健康值小于当前已知值,则更新 DP 值,并继续从该位置进行 DFS 遍历。
- 使用 DFS 遍历矩阵中的每个位置
- 结束条件 :
- 最后检查 DP 数组中终点
(m-1, n-1)
的值是否小于初始健康值health
。如果是,则表示可以在健康值大于 0 的情况下到达终点。
- 最后检查 DP 数组中终点
3、代码实现
#include <vector>
#include <limits.h>
using namespace std;
class Solution {
private:
int pos[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 上、下、左、右方向
public:
bool findSafeWalk(vector<vector<int>>& grid, int health) {
int row = grid.size();
int col = grid[0].size();
vector<vector<int>> dp(row, vector<int>(col, INT_MAX));
dp[0][0] = grid[0][0]; // 起点的健康消耗
dfs(grid, dp, row, col, 0, 0); // 从起点开始进行 DFS
return dp[row - 1][col - 1] < health; // 检查终点的最小健康值
}
void dfs(vector<vector<int>>& grid, vector<vector<int>>& dp, int row, int col, int i, int j) {
for (int k = 0; k < 4; k++) { // 四个方向
int x = i + pos[k][0];
int y = j + pos[k][1];
if (x >= 0 && x < row && y >= 0 && y < col) { // 检查边界
if (dp[x][y] > dp[i][j] + grid[x][y]) { // 更新 DP 值
dp[x][y] = dp[i][j] + grid[x][y];
dfs(grid, dp, row, col, x, y); // 继续 DFS
}
}
}
}
};
这个解法结合了 DFS 和动态规划,通过在矩阵中维护最小健康值来确保从起点到终点的路径在健康值条件下是可行的。