`
lixuanbin
  • 浏览: 137489 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Java实现基于回溯的迷宫搜索算法 --- Backtrack Based Maze Searching Algorithm in Java

阅读更多

 

 

  • 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

 

 

0
0
分享到:
评论

相关推荐

    回溯法实现0-1背包问题

    在主算法 knapsack 中,我们首先对背包集进行排序,然后调用回溯搜索函数 backtrack,穷举所有可能的选择,来找到最优解。在 backtrack 函数中,我们使用递归的方式来搜索所有可能的选择,计算每个选择的上界,并...

    利用回溯法解0-1背包问题讲解

    * 递归回溯:由于回溯法是对解空间的深度优先搜索,因此在一般情况下可用递归函数来实现回溯法。 0-1背包问题: * 问题描述:给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包容量为c。问应如何选择装入...

    Nessus-5.0.2-适用于BackTrack的版本

    Nessus-5.0.2-适用于BackTrack的版本

    回溯法解决0-1背包问题C源码

    0-1背包问题是一个经典的组合...理解并实现回溯法解决0-1背包问题有助于提升对组合优化问题和搜索策略的理解,对于学习算法和编程有重要意义。在实际应用中,还可以考虑使用动态规划等其他方法来优化解决方案的效率。

    回溯算法0-1背包问题

    回溯算法0-1背包问题代码实现。算法backtrack在最坏情况下可能需要更新当前最优解O(n-1)!)次,每次更新bestx需计算时间O(n),从而整个算法的计算时间复杂性为O(n!)。

    回溯算法-N后问题和符号三角形java算法源程序

    在给定的实验内容中,有两个基于回溯算法的Java程序,分别是“符号三角形问题”和“N后问题”。 1. 符号三角形问题: 这个问题的目标是找到所有合法的符号排列方式,使得在一个半边长度为n的三角形中,每行的“+”...

    回溯法(算法)-代码

    标题中的"回溯法(算法)-代码"表明我们将讨论如何用代码实现回溯算法。回溯法的步骤一般包括以下几个部分: 1. **定义问题状态**:明确问题的解可以用一组状态来表示,每个状态代表问题的一个可能解的一部分。 2....

    回溯算法 0-1 背包算法

    回溯算法是一种用于解决组合优化问题的搜索策略,它的核心思想是通过尝试所有可能的解决方案,逐步构造解的空间树,并在遇到无法继续扩展的分支时回溯到上一层,寻找其他可能的路径。0-1 背包问题是回溯算法的经典...

    回溯算法-N后问题和符号三角形java算法源程序.pdf

    回溯算法是一种在问题的解空间树中搜索解的算法策略,它沿着某条路径深搜,如果发现当前选择导致无法找到有效解时,就回溯到上一个决策点,尝试其他路径。在这个过程中,回溯算法能有效地避免无效的搜索,减少计算量...

    数据结构与算法-回溯算法

    ### 数据结构与算法-回溯算法 #### 回溯算法概述 回溯算法是一种系统性的搜索算法,用于解决约束满足问题。它通过不断尝试来寻找问题的解,并在遇到不可行解时返回之前的决策点,调整策略继续探索。这种方法特别...

    算法实验回溯法

    1. **解空间**:所有可能解的集合,是回溯算法搜索的范围。例如,在0/1背包问题中,解空间可以表示为n维0/1向量的空间。 2. **解向量**:一个解的表示方式,通常是一个向量,用来记录某个解的具体状态。如n皇后问题...

    回溯算法0-1背包算法c++知识.pdf

    回溯算法是一种用于解决组合优化问题的搜索算法,它的核心思想是通过深度优先搜索解空间树,当发现当前路径无法得到满足条件的解时,会返回到上一层,尝试其他可能的分支,直到找到问题的解或者搜索完整个解空间。...

    算法分析回溯法实现0-1背包(c++)归类.pdf

    最后,`knapsack` 函数是0-1背包问题的主函数,它首先调用 `QuickSort` 对物品进行排序,然后调用 `backtrack` 开始回溯搜索。在 `main` 函数中,用户输入背包的容量和物品数量,然后程序会逐个读取物品的重量和价值...

    Step-by-Step-Backtrack-5-and-Wireless-Hacking-Basics-PDF.pdf

    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 ...

    Python基于回溯法解决01背包问题实例

    回溯法是一种通过深度优先搜索解决问题的算法,它尝试构建解决方案的候选树,并在发现无法找到有效解时撤销最近的选择,返回上一层继续探索其他可能的分支。这种方法特别适用于解决约束满足问题,如组合优化问题。 ...

    回溯法实现01背包问题JAVA版.txt

    ### 回溯法实现01背包问题JAVA版 #### 核心知识点解析: **1. 01背包问题概述:** 01背包问题是一种经典的组合优化问题,在计算机科学与运筹学领域广泛应用。该问题的基本设定是:给定一系列物品,每个物品具有...

    回溯法的应用-0-1背包等问题.docx

    回溯法是一种在问题的解空间树中,通过试探...通过这个实验,我们可以深入了解回溯法的原理,掌握如何设计和分析回溯算法,以及如何实现并测试它。这有助于提高解决实际问题的能力,并为解决更复杂的优化问题奠定基础。

    回溯法编写0-1背包程序 C++

    以下是一个简单的C++实现0-1背包问题的回溯算法概述: ```cpp #include using namespace std; const int MAXN = 100; // 物品数量上限 const int MAXW = 1000; // 背包容量上限 int n, W; // n为物品数量,W为...

Global site tag (gtag.js) - Google Analytics