标题:机器人走迷宫破壁解法(适用于走迷宫、最短路径算法)-20200412
问题描述:
- 一块矩形方格,含有障碍和可通行格子,求从某一点到另外一点的最短距离?N*M的矩阵;
其中,1代表障碍,0代表可通行;示例:给定二维矩阵
0 0 1 0
0 1 0 0
0 0 0 0
0 0 0 0
出发点坐标[0, 0],终点坐标[0, 3];
假如最多有一次破障碍格子的机会,java编写int solve(int[][] grids, int[] start, int[] end)返回最短距离;BFS
思路:
(1)当然可用dfs深度优先遍历;但是,有没有BFS呢?
dfs的特点:找到每条完整路径再返回,不到黄河心不死;
bfs:尽量扩散,看是否能走到终点;
(2)考虑BFS,每次按层遍历,在破壁和不破壁的情况下,最远可以走多远;已经破壁则不能再破壁了;
(3)那么有人问?到底何时破壁呢?尽早破壁,尽快扩散;基于扩散的点再次扩散;尽早到达最远;
例如:
0 0 1 0
0 1 0 0
0 0 0 0
0 0 0 0
第一层壁不破,更待何时?破除四周的障碍,谁最早到达外层,谁就获胜。因为各自距离是相等的,是无权图。
第一步:[0, 0]的下一层点集:[0, 1],[1, 0];这是在破壁和不破壁达到的最远点;
第二步:基于[0, 1],[1, 0],最多可以扩散哪些点?同样,找破壁和不破壁到达节点的并集;已经访问过的就不要再访问了。
[0, 1]可以访问的点:破壁的才能访问,同时记录状态:已经破壁一次。[0, 2],[1, 1];
[1, 0]可以访问的[2,0];不破壁的情况下可以访问。
并集:[0, 2],[1, 1],[2,0];前两个是破壁一次访问的,后一个是非破壁访问的。
第三步:
[0, 2]可达[0, 3];其实就是终点,直接可达return;
[1, 1],[2,0]:不用看了;
下面看bfs解法;
dfs思路:
(1)[0, 0]到[0, 3]的距离最短,[0,0]等价于相邻点[0, 1],[1, 0]分别到终点的距离最小值,再加上邻近的1;对于是否破壁求分支;
dfs([0,0],[0,3])等价于:
min(dfs([0,1],[0,3],破壁),dfs([0,1],[0,3],未用破壁), dfs([1,0],[0,3],破壁),dfs([1,0],[0,3],未破壁));
不需要破壁时就不用;考虑破壁与否和四个方向求最小值;遍历次数太多;
更复杂场景,若给多次机会,如何解呢?亦是尽早破壁,走得最远;
package robot;
import java.util.LinkedList;
import java.util.Queue;
public class SolutionUpdate {
int[][] direct = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
// 方格的bfs;
public int bfs(int[][] grids, int[] start, int[] end) {
// 写是否已经访问的状态;
int[][] state = new int[grids.length][grids[0].length];
Queue queue = new LinkedList();
// 入队时标记是否破壁。0:未使用;1:已使用;
state[start[0]][start[1]] = 1;
queue.offer(new int[]{start[0], start[1], 0});
int count = 0;
while (!queue.isEmpty()) {
// 扩散开始
count++;
// 每次要把扩散一次的节点全部拿出来,才能进行下一步扩散;
System.out.println("queue size is:" + queue.size());
int size = queue.size();
for (int inx = 0; inx < size; inx++) {
int[] node = (int[]) queue.poll();
// 当扩散到终点就拉出来;注意:若要打印最短路径,到达终点时可以拉出来;
if (node[0] == end[0] && node[1] == end[1]) {
// 起点塞进来已经加1,故要减去;
return count - 1;
}
for (int[] item : direct) {
int nextX = node[0] + item[0];
int nextY = node[1] + item[1];
if (nextX >= 0 && nextX <= grids.length - 1
&& nextY >= 0 && nextY <= grids[0].length - 1
&& state[nextX][nextY] != 1) {
System.out.println("queue size: " + queue.size()+"--;" +node[0] + "," + node[1] + ";" + "--:" + nextX + "," + nextY + "");
if (node[2] == 0 && grids[nextX][nextY] == 0) {
// 不用破壁
queue.offer(new int[]{nextX, nextY, 0});
state[nextX][nextY] = 1;
} else if (node[2] == 0 && grids[nextX][nextY] == 1) {
// 使用破壁
queue.offer(new int[]{nextX, nextY, 1});
state[nextX][nextY] = 1;
} else if (node[2] == 1 && grids[nextX][nextY] == 0) {
// 不能再使用破壁;乖乖地按常理走吧。
queue.offer(new int[]{nextX, nextY, 0});
state[nextX][nextY] = 1;
} else {
// node[2] == 1 && grids[nextX][nextY] == 1
// 不能走
state[nextX][nextY] = 1;
}
}
}
}
System.out.println("----------");
}
return -1;
}
}
测试类:
int[][] grids = {
{0, 0, 1, 0},
{0, 1, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}
};
int[] start = {0, 0};
int[] end = {0, 3};
结果:
3