- Definition:
0. use a 2d array of integers to represent a maze;
1. 0 for passable, 1 if not;
2. the first element (maze[0][0]) is the entry;
3. the last element (maze[maze.length - 1][maze[maze.length - 1].length - 1]) is the exit;
eg.
0, 1, 1
1, 0, 1
1, 1, 0
4. horizontal, vertical and diagonal moves are allowed;
- Question:
Find out all the possible ways out and figure out the shortest one.
- Solution:
0. start from the entry point of the maze, define and initialize three pointers: previous, current and next;
1. search all passable points next to current point and store them in a linked list;
2. remove one from the passable list as next, point previous to current and point current to next, then push the rest passables into a stack for later backtracking;
3. if no more passable point is found at the current position, pop one point from the stack, go back to the right place and choose a different move;
4. wrap 1-3 in a loop until all paths of the maze are searched.
- Codes:
0. MazeSearcher
package co.speedar.dsal.maze; import java.util.LinkedList; import java.util.List; import java.util.Stack; /** * Search all the ways out in a given maze. * * @author ben * @creation 2014年4月13日 */ public class MazeSearcher { /** * 2d integer matrix, representing the maze.<br/> * Definition: <br/> * 1. 0 for passable, 1 if not;<br/> * 2. the first element (maze[0][0]) is the entry;<br/> * 3. the last element (maze[maze.length - 1][maze[maze.length - 1].length - 1]) is the exit;<br/> * eg.<br/> * 0, 1, 1<br/> * 1, 0, 1<br/> * 1, 1, 0<br/> */ private int[][] maze; /** * current search trunk<br/> * {currentLoc,preLoc} */ private List<Point[]> currentPath = new LinkedList<Point[]>(); /** * holds candidate movables, used for backtracking<br/> * {currentLoc,preLoc,nextLoc} */ private Stack<Point[]> stack = new Stack<Point[]>(); /** * holds all the solutions. */ private List<List<Point[]>> paths = new LinkedList<List<Point[]>>(); public MazeSearcher(int[][] maze) { super(); this.maze = maze; } /** * find out all the possible paths */ public void searchAllPaths() { Point current = new Point(0, 0); Point pre = null; Point next = null; // add the start point currentPath.add(new Point[] { current, pre }); List<Point> movables = searchNext(current, pre); do { if (movables != null && !movables.isEmpty()) { // still movable next = movables.remove(0); if (movables != null && !movables.isEmpty()) { // has optional paths, push them into the stack for backtracking for (int i = 0; i < movables.size(); i++) { // {current position, pre position, next position} Point temPoint = movables.remove(0); System.out.println("stack.push: " + "{" + current + "," + pre + "," + temPoint + "}"); stack.push(new Point[] { current, pre, temPoint }); } } pre = current; current = next; currentPath.add(new Point[] { current, pre }); next = null; } else { // backtrack if (!stack.isEmpty() && !currentPath.isEmpty()) { Point[] backtrackPoints = stack.pop(); System.out.println("stack.pop: " + "{" + backtrackPoints[0] + "," + backtrackPoints[1] + "," + backtrackPoints[2] + "}"); Point[] currentPathPoints; while (!currentPath.isEmpty()) { currentPathPoints = currentPath.remove(currentPath .size() - 1); if (currentPathPoints[0].equals(backtrackPoints[0]) && ((currentPathPoints[1] == null && backtrackPoints[1] == null) || currentPathPoints[1] .equals(backtrackPoints[1]))) { // track back to the right position currentPath.add(currentPathPoints); break; } } // choose a different position at that point next = backtrackPoints[2]; pre = backtrackPoints[1]; current = backtrackPoints[0]; pre = current; current = next; currentPath.add(new Point[] { current, pre }); next = null; } } // check and save path if exit if (isExit(current)) { rememberCurrentPath(); } // search next movables movables = searchNext(current, pre); // print out current path printCurrentPath(); } while ((movables != null && !movables.isEmpty()) || !stack.isEmpty()); // continue loop if still movable or backtrackable } public void printCurrentPath() { for (Point[] currentPoints : currentPath) { System.out.print(currentPoints[0] + " -> "); } if (isExit(currentPath.get(currentPath.size() - 1)[0])) { System.out.print("end"); System.out.println(); System.out.println("a way out found!"); } else { System.out.println(); } } public void printShortestPath() { int shortestLength = paths.get(0).size(); List<Point[]> shortestPath = paths.get(0); for (List<Point[]> tempPath : paths) { if (tempPath.size() < shortestLength) { shortestLength = tempPath.size(); shortestPath = tempPath; } } System.out.println("The shortest path is: "); for (Point[] currentPoints : shortestPath) { System.out.print(currentPoints[0] + " -> "); } System.out.println("end"); } public void printAllPaths() { System.out.println("Here are all the ways out: "); for (List<Point[]> currentPoints : paths) { for (Point[] points : currentPoints) { System.out.print(points[0] + " -> "); } System.out.println("end"); } } private void rememberCurrentPath() { List<Point[]> currentPoints = new LinkedList<Point[]>(); for (Point[] points : currentPath) { currentPoints.add(points); } paths.add(currentPoints); } /** * the current point is exit or not * * @param current * @return */ private boolean isExit(Point current) { if (maze.length - 1 == current.x && maze[maze.length - 1].length - 1 == current.y && isAvailable(current)) { return true; } return false; } /** * search all next movable positions<br/> * * @param current * @param pre * @return */ private List<Point> searchNext(Point current, Point pre) { Point next = null; List<Point> movables = new LinkedList<Point>(); if (isExit(current)) { return movables; } next = searchNorth(current); checkAndSaveNext(current, pre, next, movables); next = searchNorthEast(current); checkAndSaveNext(current, pre, next, movables); next = searchEast(current); checkAndSaveNext(current, pre, next, movables); next = searchSouthEast(current); checkAndSaveNext(current, pre, next, movables); next = searchSouth(current); checkAndSaveNext(current, pre, next, movables); next = searchSouthWest(current); checkAndSaveNext(current, pre, next, movables); next = searchWest(current); checkAndSaveNext(current, pre, next, movables); next = searchNorthWest(current); checkAndSaveNext(current, pre, next, movables); return movables; } /** * 1.check if null;<br/> * 2.check if available;<br/> * 3.check if duplicated to previous;<br/> * 4.check if circled; * * @param current * @param pre * @param next * @param movables */ private void checkAndSaveNext(Point current, Point pre, Point next, List<Point> movables) { if (next != null && isAvailable(next) && !next.equals(pre) && !containsCircle(next)) { movables.add(next); } } private boolean containsCircle(Point next) { for (Point[] path : currentPath) { if (path[0].equals(next)) { return true; } } return false; } private boolean isAvailable(Point next) { if (maze[next.x][next.y] == 0) { return true; } return false; } private Point searchNorthWest(Point current) { Point next = null; if (current.x - 1 >= 0 && current.y - 1 >= 0) { next = new Point(current.x - 1, current.y - 1); } return next; } private Point searchWest(Point current) { Point next = null; if (current.y - 1 >= 0) { next = new Point(current.x, current.y - 1); } return next; } private Point searchSouthWest(Point current) { Point next = null; if (current.x + 1 < maze.length && current.y - 1 >= 0) { next = new Point(current.x + 1, current.y - 1); } return next; } private Point searchSouth(Point current) { Point next = null; if (current.x + 1 < maze.length) { next = new Point(current.x + 1, current.y); } return next; } private Point searchSouthEast(Point current) { Point next = null; if (current.x + 1 < maze.length && current.y + 1 < maze[current.x + 1].length) { next = new Point(current.x + 1, current.y + 1); } return next; } private Point searchEast(Point current) { Point next = null; if (current.y + 1 < maze[current.x].length) { next = new Point(current.x, current.y + 1); } return next; } private Point searchNorthEast(Point current) { Point next = null; if (current.x - 1 >= 0 && current.y + 1 < maze[current.x - 1].length) { next = new Point(current.x - 1, current.y + 1); } return next; } private Point searchNorth(Point current) { Point next = null; if (current.x - 1 >= 0) { next = new Point(current.x - 1, current.y); } return next; } }
1. Point
package co.speedar.dsal.maze; /** * Simulates a point in the maze. * * @author ben * @creation 2014年4月14日 */ public class Point { /** * row index */ int x; /** * column index */ int y; Point(int x, int y) { this.x = x; this.y = y; } @Override public boolean equals(Object obj) { if (obj instanceof Point) { Point that = (Point) obj; if (this.x == that.x && this.y == that.y) { return true; } } return false; } @Override public String toString() { return "(" + this.x + "," + this.y + ")"; } }
2. MazeSearcherTest
/** * */ package co.speedar.dsal.maze; /** * @author ben * @creation 2014年4月14日 */ public class MazeSearcherTest { /** * @param args */ public static void main(String[] args) { int[][] maze = new int[4][4]; int[] tempInts; tempInts = new int[] { 0, 0, 1, 1 }; maze[0] = tempInts; tempInts = new int[] { 1, 1, 0, 1 }; maze[1] = tempInts; tempInts = new int[] { 1, 0, 1, 0 }; maze[2] = tempInts; tempInts = new int[] { 0, 1, 0, 0 }; maze[3] = tempInts; MazeSearcher searcher = new MazeSearcher(maze); searcher.searchAllPaths(); searcher.printAllPaths(); searcher.printShortestPath(); } }
- Test Result:
(0,0) -> (0,1) -> (0,0) -> (0,1) -> (1,2) -> stack.push: {(1,2),(0,1),(2,1)} (0,0) -> (0,1) -> (1,2) -> (2,3) -> stack.push: {(2,3),(1,2),(3,2)} (0,0) -> (0,1) -> (1,2) -> (2,3) -> (3,3) -> end a way out found! stack.pop: {(2,3),(1,2),(3,2)} (0,0) -> (0,1) -> (1,2) -> (2,3) -> (3,2) -> stack.push: {(3,2),(2,3),(2,1)} (0,0) -> (0,1) -> (1,2) -> (2,3) -> (3,2) -> (3,3) -> end a way out found! stack.pop: {(3,2),(2,3),(2,1)} (0,0) -> (0,1) -> (1,2) -> (2,3) -> (3,2) -> (2,1) -> (0,0) -> (0,1) -> (1,2) -> (2,3) -> (3,2) -> (2,1) -> (3,0) -> stack.pop: {(1,2),(0,1),(2,1)} (0,0) -> (0,1) -> (1,2) -> (2,1) -> stack.push: {(2,1),(1,2),(3,0)} (0,0) -> (0,1) -> (1,2) -> (2,1) -> (3,2) -> stack.push: {(3,2),(2,1),(3,3)} (0,0) -> (0,1) -> (1,2) -> (2,1) -> (3,2) -> (2,3) -> (0,0) -> (0,1) -> (1,2) -> (2,1) -> (3,2) -> (2,3) -> (3,3) -> end a way out found! stack.pop: {(3,2),(2,1),(3,3)} (0,0) -> (0,1) -> (1,2) -> (2,1) -> (3,2) -> (3,3) -> end a way out found! stack.pop: {(2,1),(1,2),(3,0)} (0,0) -> (0,1) -> (1,2) -> (2,1) -> (3,0) -> Here are all the ways out: (0,0) -> (0,1) -> (1,2) -> (2,3) -> (3,3) -> end (0,0) -> (0,1) -> (1,2) -> (2,3) -> (3,2) -> (3,3) -> end (0,0) -> (0,1) -> (1,2) -> (2,1) -> (3,2) -> (2,3) -> (3,3) -> end (0,0) -> (0,1) -> (1,2) -> (2,1) -> (3,2) -> (3,3) -> end The shortest path is: (0,0) -> (0,1) -> (1,2) -> (2,3) -> (3,3) -> end
相关推荐
在主算法 knapsack 中,我们首先对背包集进行排序,然后调用回溯搜索函数 backtrack,穷举所有可能的选择,来找到最优解。在 backtrack 函数中,我们使用递归的方式来搜索所有可能的选择,计算每个选择的上界,并...
* 递归回溯:由于回溯法是对解空间的深度优先搜索,因此在一般情况下可用递归函数来实现回溯法。 0-1背包问题: * 问题描述:给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包容量为c。问应如何选择装入...
Nessus-5.0.2-适用于BackTrack的版本
0-1背包问题是一个经典的组合...理解并实现回溯法解决0-1背包问题有助于提升对组合优化问题和搜索策略的理解,对于学习算法和编程有重要意义。在实际应用中,还可以考虑使用动态规划等其他方法来优化解决方案的效率。
回溯算法0-1背包问题代码实现。算法backtrack在最坏情况下可能需要更新当前最优解O(n-1)!)次,每次更新bestx需计算时间O(n),从而整个算法的计算时间复杂性为O(n!)。
在给定的实验内容中,有两个基于回溯算法的Java程序,分别是“符号三角形问题”和“N后问题”。 1. 符号三角形问题: 这个问题的目标是找到所有合法的符号排列方式,使得在一个半边长度为n的三角形中,每行的“+”...
标题中的"回溯法(算法)-代码"表明我们将讨论如何用代码实现回溯算法。回溯法的步骤一般包括以下几个部分: 1. **定义问题状态**:明确问题的解可以用一组状态来表示,每个状态代表问题的一个可能解的一部分。 2....
回溯算法是一种用于解决组合优化问题的搜索策略,它的核心思想是通过尝试所有可能的解决方案,逐步构造解的空间树,并在遇到无法继续扩展的分支时回溯到上一层,寻找其他可能的路径。0-1 背包问题是回溯算法的经典...
回溯算法是一种在问题的解空间树中搜索解的算法策略,它沿着某条路径深搜,如果发现当前选择导致无法找到有效解时,就回溯到上一个决策点,尝试其他路径。在这个过程中,回溯算法能有效地避免无效的搜索,减少计算量...
### 数据结构与算法-回溯算法 #### 回溯算法概述 回溯算法是一种系统性的搜索算法,用于解决约束满足问题。它通过不断尝试来寻找问题的解,并在遇到不可行解时返回之前的决策点,调整策略继续探索。这种方法特别...
1. **解空间**:所有可能解的集合,是回溯算法搜索的范围。例如,在0/1背包问题中,解空间可以表示为n维0/1向量的空间。 2. **解向量**:一个解的表示方式,通常是一个向量,用来记录某个解的具体状态。如n皇后问题...
回溯算法是一种用于解决组合优化问题的搜索算法,它的核心思想是通过深度优先搜索解空间树,当发现当前路径无法得到满足条件的解时,会返回到上一层,尝试其他可能的分支,直到找到问题的解或者搜索完整个解空间。...
最后,`knapsack` 函数是0-1背包问题的主函数,它首先调用 `QuickSort` 对物品进行排序,然后调用 `backtrack` 开始回溯搜索。在 `main` 函数中,用户输入背包的容量和物品数量,然后程序会逐个读取物品的重量和价值...
Backtrack无线攻防步步为营 Backtrack 5 R3 is a notorious Digital Forensic and Intrusion Detection software bundle with a whole lot of tools for Penetration Testing, It is based on Linux and includes ...
回溯法是一种通过深度优先搜索解决问题的算法,它尝试构建解决方案的候选树,并在发现无法找到有效解时撤销最近的选择,返回上一层继续探索其他可能的分支。这种方法特别适用于解决约束满足问题,如组合优化问题。 ...
### 回溯法实现01背包问题JAVA版 #### 核心知识点解析: **1. 01背包问题概述:** 01背包问题是一种经典的组合优化问题,在计算机科学与运筹学领域广泛应用。该问题的基本设定是:给定一系列物品,每个物品具有...
回溯法是一种在问题的解空间树中,通过试探...通过这个实验,我们可以深入了解回溯法的原理,掌握如何设计和分析回溯算法,以及如何实现并测试它。这有助于提高解决实际问题的能力,并为解决更复杂的优化问题奠定基础。
以下是一个简单的C++实现0-1背包问题的回溯算法概述: ```cpp #include using namespace std; const int MAXN = 100; // 物品数量上限 const int MAXW = 1000; // 背包容量上限 int n, W; // n为物品数量,W为...