這實際上是BFS的入門級問題,我以初學者的姿態研究,若有不足請指正。java
BFS的核心是利用query的先進先出原則,而本題的回溯用到了stack的後進先出原則,能夠說是對兩種數據結構的複習。node
在解題過程當中對Java的對象複製的本質有了更加深入的理解,具體發在另外一篇博文」Java對象複製的背後「算法
本題是基本的BFS原理,附加利用二維數組構造象限,利用二維boolean數組構造visited,和利用二維dir數組構建上下左右的移動。數組
如下是代碼數據結構
這裏的queue是存放每層點的數據結構。(從上一層前往下一層),有且它只保存一層的數據。這也符合BFS的特質。this
import java.util.LinkedList; import java.util.Queue; import java.util.Stack; public class solution { public static int M = 5; public static int N = 5; public static void main(String args[]) { int maze[][] = { { 0, 1, 0, 0, 0 }, { 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0 }, { 0, 1, 1, 1, 0 }, { 0, 0, 0, 1, 0 } }; if (maze_path(maze)) System.out.println("The solution is showed above"); else System.out.println("It is not feasible"); } public static boolean maze_path(int MAZE[][]) { int maze[][] = MAZE; boolean visited[][] = new boolean[5][5]; Queue<Node> queue = new LinkedList<Node>(); Stack<Node> path = new Stack<Node>(); Node start = new Node(0, 0); visited[0][0] = true; Node end = new Node(4, 4); Node cur = new Node(0, 0, 0, 0); Node move = new Node(0, 0, 0, 0); int dir[][] = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } }; queue.offer(start); while (!queue.isEmpty()) { cur = queue.poll(); path.push(cur); for (int i = 0; i < 4; i++) { move.x = cur.x + dir[i][0]; move.y = cur.y + dir[i][1]; move.prev_x = cur.x; move.prev_y = cur.y; if (move.x == end.x && move.y == end.y) { while (!path.isEmpty()) { Node show_path = path.pop(); if (move.prev_x == show_path.x && move.prev_y == show_path.y) { System.out.println("(" + show_path.x + ", " + show_path.y + ")"); move = show_path; } } return true; } if (move.x >= 0 && move.x < M && move.y >= 0 && move.y < N && (maze[move.x][move.y] == 0) && (!visited[move.x][move.y])) { Node new_node = new Node(move.x, move.y, move.prev_x, move.prev_y); queue.offer(new_node); visited[move.x][move.y] = true; } } } return false; } }
如下是Node類對象
public class Node { public int x; public int y; public int prev_x; public int prev_y; boolean value; public Node(int X, int Y, int PREV_X, int PREV_Y) { this.x = X; this.y = Y; this.prev_x = PREV_X; this.prev_y = PREV_Y; } public Node(int X, int Y) { this.x = X; this.y = Y; } }
值得注意的是,爲了回溯的須要,在node中還添加了prev_x和prev_yblog
在解題過程當中我在思路上遇到過兩個瓶頸it
1. 最初我認爲BFS的算法不能解決這個迷宮問題,當時的想法是:好比總有一個點是一條岔路,而後有一條看似能走通的路和一條不能走通的路,若是經過標記點的方式,可能在不能走通的路上把能走通的點標爲了false,因而都走不通了。其實這個想法仔細想一想就不可能,由於若是那條所謂不能走通的路上存在一個可以讓另外一條路走通的點,那麼它自己就確定是可以走通的。如今看起來很容易的point,當時確實困擾了我好久。io
2. 在回溯時,利用
while (!path.isEmpty()) { Node show_path = path.pop(); if (move.prev_x == show_path.x && move.prev_y == show_path.y) { System.out.println("(" + show_path.x + ", " + show_path.y + ")"); move = show_path; } }這段代碼能夠完成回溯,經過stack的先進後出原則,經過回溯到上一個節點的prev則可以繼續找到更上一個的,進而完成所有回溯。