前言
BFS作为图遍历的基础遍历,是操作图的基本功,而有时候并不是每条边权重都是一样的,此时就需要选出最优路径先走,把位置先占着。可通过优先队列来取得最优路径,建好堆,一次logN就能拿到最优路径。
一、到达角落需要移除障碍物的最小数目
二、带优先级的BFS
1、DFS超时练习(即使剪枝,过于暴力)
// dfs超时。
public class MinimumObstacles {
/*
dfs从起点到终点,记录障碍个数。选取最小障碍数。
*/
public int minimumObstacles(int[][] grid) {
dfs(grid, 0, 0, 0);
return min;
}
int min = 1 << 30;
private void dfs(int[][] grid, int i, int j, int cur) {
// 剪枝,当走这条路需要去除的障碍物太多时,则排除此路。
if (cur >= min) return;
int m = grid.length, n = grid[0].length;
if (i == -1 || -1 == j || i == m || n == j || grid[i][j] == -1) return;
if (grid[i][j] == 1) ++cur;
if (i == m - 1 && j == n - 1) {
if (cur < min) min = cur;
return;
}
int val = grid[i][j];
grid[i][j] = -1;// 表示该格子已经被访问过。
dfs(grid, i - 1, j, cur);
dfs(grid, i + 1, j, cur);
dfs(grid, i, j - 1, cur);
dfs(grid, i, j + 1, cur);
grid[i][j] = val;// 回溯之后,要表示该格子没有被走过。
}
}
2、带优先级的BFS
class MinimumObstacles2 {
/*
变种bfs--优先级bfs + 原地空间利用,记录路径上的障碍数.
但是不同路径走到相同格子会有选择问题,要选择到该格子碰到的最小障碍物,则需要对障碍物进行排序,选障碍物少路径bfs.
*/
public int minimumObstacles(int[][] grid) {
int m = grid.length, n = grid[0].length;
// 优先级bfs用到的优先队列。
PriorityQueue<int[]> pQue = new PriorityQueue<>(Comparator.comparingInt(p -> p[0]));
int[] init = new int[3];//分别表示到达当前格子经过的障碍数、当前格子的横坐标、纵坐标。
pQue.add(init);
while (true) {
int[] cur = pQue.poll();
int w = cur[0], i = cur[1], j = cur[2];
if (i == m - 1 && j == n - 1) return w;
else if (i >= 0 && 0 <= j && i < m && n > j && grid[i][j] != -1) {
pQue.offer(new int[]{w + grid[i][j], i - 1, j});
pQue.offer(new int[]{w + grid[i][j], i + 1, j});
pQue.offer(new int[]{w + grid[i][j], i, j - 1});
pQue.offer(new int[]{w + grid[i][j], i, j + 1});
// 设置该节点已在最优路径上了。
grid[i][j] = -1;
}
// else的情况,就是当前ij不合法或者该节点被优先级高的路径走过。
}
}
}
总结
1)如何解决带权重的图,起点到终点的最短路径,可用优先队列 + BFS每层从队列中选出最优路径再往前走。