一、网格中的最短路径
1.1 可以消除障碍物
LeetCode1293:网格中的最短路径
给你一个 m * n 的网格,其中每个单元格不是 0(空)就是 1(障碍物)。每一步,您都可以在空白单元格中上、下、左、右移动。如果您 最多 可以消除 k 个障碍物,请找出从左上角 (0, 0) 到右下角 (m-1, n-1) 的最短路径,并返回通过该路径所需的步数。如果找不到这样的路径,则返回 -1。
class Solution {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int m = sc.nextInt();//网格的长
int n = sc.nextInt();//网格的宽
int k = sc.nextInt();
int[][] grid = new int[m][n];
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
grid[i][j] = sc.nextInt();
}
}
System.out.println(shortestPath(grid,k));
}
public int shortestPath(int[][] grid, int k) {
int m = grid.length;
int n = grid[0].length;
if(k >= m + n -3) return m + n - 2;
boolean[][] visited = new boolean[m][n];
int res = backtrack(grid,0,0,m,n,0,k,visited);
return res == Integer.MAX_VALUE ? -1 : res;
}
public int backtrack(int[][] grid,int i,int j,int m,int n,int count,int k,boolean[][] visited){
if(i < 0 || i >= m || j < 0 || j >= n) return Integer.MAX_VALUE;//递归出口
if(i == m-1 && j == n-1) return count;//结果
if(visited[i][j]) return Integer.MAX_VALUE;
//排除障碍物
if(grid[i][j] == 1){
if(k > 0) k--;
else return Integer.MAX_VALUE;
}
visited[i][j] = true;
//取4个方向可能路径的最小值返回
int min4 = Integer.MAX_VALUE;
min4 = Math.min(min4,backtrack(grid,i-1,j,m,n,count+1,k,visited));
min4 = Math.min(min4,backtrack(grid,i+1,j,m,n,count+1,k,visited));
min4 = Math.min(min4,backtrack(grid,i,j-1,m,n,count+1,k,visited));
min4 = Math.min(min4,backtrack(grid,i,j+1,m,n,count+1,k,visited));
//回溯
visited[i][j] = false;
return min4;
}
}
【法二】visited访问标记数组三维扩展 (用于比较)
本题比较麻烦些,增加了障碍物且可以有k次机会消除,单纯有障碍物就是标准的BFS处理即可,但有k次消除障碍物,就需要增加一个维度来记录同一个节点被访问的时候 已经使用消除障碍物的次数。:
链接:作者:jin-129
public int shortestPath(int[][] grid, int k) {
int m = grid.length;
int n = grid[0].length;
// 非法参数处理
if (validateInputParams(k, m, n)) {
return -1;
}
// 特殊场景处理
if (m == 1 && n == 1) {
return 0;
}
// BFS搜索节点访问标识, 此题要求有k个消除障碍的机会,所以每个节点除了标记是否被访问过
// 还要记录搜索到此节点时消除了几个障碍。消除相同障碍的下一层节点 可以剪枝(因为有相同代价更早的节点了)
// 例子:k=1, BFS是按层级来的,绕道的层级扩展越多
// 坐标(0,2)可以为消除(0,1)障碍过来的 visited[0][2][1] = 1,搜索层级为2
// 也可能为不消除任何障碍过来的 visited[0][2][0] = 1,层级为6,为扩展搜索不通障碍消除数提供区分
// 0 1 0 0 0 1 0 0
// 0 1 0 1 0 1 0 1
// 0 0 0 1 0 0 1 0
// 二维标记位置,第三维度标记 到此节点的路径处理障碍总个数
int[][][] visited = new int[m][n][k+1];
// 初始步数为0,m=n=1的特殊场景已处理
int minSteps = 0;
// 初始位置标记已访问
visited[0][0][0