回溯算法经典应用之—迷宫问题 (Java)

来源:互联网 发布:golang 连接mongodb 编辑:程序博客网 时间:2024/05/21 09:31
1、回溯算法简介
回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。用回溯算法解决问题的一般步骤为:
1)、定义一个解空间,它包含问题的解。
2)、利用适于搜索的方法组织解空间。
3)、利用深度优先法搜索解空间。
4)、利用限界函数避免移动到不可能产生解的子空间。

问题的解空间通常是在搜索问题的解的过程中动态产生的,这是回溯算法的一个重要特性。



2、问题定义

问题:给定一个迷宫,找到从入口到出口的所有可行路径。如下图所示:



思路:

由于路径不能重复进入矩阵的格子,还需要定义和字符矩阵大小一样的布尔值矩阵,用来标识路径是否已经进入每个格子。 当矩阵中坐标为(row,col)的格子和路径字符串中相应的字符一样时,从4个相邻的格子(row,col-1),(row-1,col),(row,col+1)以及(row+1,col)中去定位路径字符串中下一个字符如果4个相邻的格子都走不通时,表明当前路径不正确,我们需要回到前一个,然后重新规划路线。一直重复这个过程,直到找到终点。

解题步骤:
1)、从起点开始,逐步向其它路径四周扩展路径。
2)、每走一步判断,如果未到达继续四周扩展路径。
3)、记录下路径,如果走到思路则回退到上一步。

先贴上第一个版本的代码,次代码只能返回是否有路径,比较简单一点:

package com.qian.backtracing;public class Maze {public boolean hasPath(boolean[][] road, int sRow, int sCol, int tRow, int tCol) {boolean[][] hasVisited = new boolean[road.length][road[0].length];if(!road[sRow][sCol] || !road[tRow][tCol]) return false;for (int i = 0; i < road.length; i++) {for (int j = 0; j < road[0].length; j++) {if(road[i][j])System.out.print("√,");elseSystem.out.print("x,");}System.out.println();}boolean rst = hasPathCore(road, sRow, sCol, tRow, tCol, hasVisited);return rst;}/** * 回溯递归函数  * @param road  路线图 * @param row行号 * @param col列号 * @param tRow终点行号 * @param tCol终点列号 * @param hasVisited是否被访问数组 * @return */public boolean hasPathCore(boolean[][] road, int row, int col, int tRow, int tCol,boolean[][] hasVisited) {int cols = road[0].length;int rows = road.length;//System.out.println(cols + ";;" + rows );if (col < 0|| col >= cols|| row < 0|| row >= rows|| !road[row][col] //路是通的|| hasVisited[row][col])return false;if (row == tRow && col == tCol) //递归函数的出口return true;hasVisited[row][col] = true;if(hasPathCore(road, row - 1, col, tRow, tCol, hasVisited) || hasPathCore(road, row, col - 1, tRow, tCol, hasVisited) || hasPathCore(road, row + 1, col, tRow, tCol, hasVisited)|| hasPathCore(road, row, col + 1, tRow, tCol, hasVisited)) {return true;}hasVisited[row][col] = false;return false;}public static void main(String[] args) {boolean[][] road = {{true,true,true},{false,true,false},{false,true,true}};boolean[][] road2 = {{true ,true ,true ,false,false}, {false,false,true ,false,false}, {false,true ,true ,false,false}, {false,true ,false,false,false}, {false,true ,true ,true ,true }};Maze maze = new Maze();System.out.println(maze.hasPath(road2, 0, 0, 4, 4));}}

返回值为true;


再贴上完整版的代码,能找到所有路径并输出:

package com.qian.backtracing;import java.util.ArrayList;public class Maze2 {private int sum = 0;private  ArrayList<ArrayList<String>> paths = new ArrayList<>();private ArrayList<String> path = new ArrayList<String>();public int hasPath(boolean[][] road, int sRow, int sCol, int tRow, int tCol) {boolean[][] hasVisited = new boolean[road.length][road[0].length];if (!road[sRow][sCol] || !road[tRow][tCol])return 0;hasPathCore(road, sRow, sCol, tRow, tCol, hasVisited,0);return sum;}/** * 回溯递归函数 * @param road  路线图 * @param row行号 * @param col列号 * @param tRow终点行号 * @param tCol终点列号 * @param hasVisited是否被访问数组 * @param depth访问深度  用于路径的添加 */public void hasPathCore(boolean[][] road, int row, int col, int tRow,int tCol, boolean[][] hasVisited,int depth) {int cols = road[0].length;int rows = road.length;if (col < 0 || col >= cols || row < 0 || row >= rows || !road[row][col] // 路是通的|| hasVisited[row][col]) {return;}path.add("(" + row + "," + col + ")");if (row == tRow && col == tCol) {// 递归函数的出口sum++;paths.add(new ArrayList<String>(path));path.remove(depth);return;} else {hasVisited[row][col] = true;hasPathCore(road, row - 1, col, tRow, tCol, hasVisited,depth + 1);hasPathCore(road, row, col - 1, tRow, tCol, hasVisited,depth + 1);hasPathCore(road, row + 1, col, tRow, tCol, hasVisited,depth + 1);hasPathCore(road, row, col + 1, tRow, tCol, hasVisited,depth + 1);// return true;path.remove(depth);hasVisited[row][col] = false;// return false;}}public static void main(String[] args) {boolean[][] road = { { true, true, true }, { false, true, false },{ false, true, true } };boolean[][] road2 = { { true , true , true , true , true  },{ false, false, true , false, true  },{ false, true , true , true , true  },{ false, true , false, false, true  },{ false, true , true , true , true } };//打印路径System.out.println("地图为:");for (int i = 0; i < road2.length; i++) {for (int j = 0; j < road2[0].length; j++) {if (road2[i][j])System.out.print("√,");elseSystem.out.print("x,");}System.out.println();}Maze2 maze = new Maze2();System.out.println("一共有" + maze.hasPath(road2, 0, 0, 4, 4) + "条路径");//打印路径System.out.println("分别为:");for (ArrayList<String> p : maze.paths) {System.out.println(p);}}}


输出结果为:

地图为:√,√,√,√,√,x,x,√,x,√,x,√,√,√,√,x,√,x,x,√,x,√,√,√,√,一共有4条路径分别为:[(0,0), (0,1), (0,2), (1,2), (2,2), (2,1), (3,1), (4,1), (4,2), (4,3), (4,4)][(0,0), (0,1), (0,2), (1,2), (2,2), (2,3), (2,4), (3,4), (4,4)][(0,0), (0,1), (0,2), (0,3), (0,4), (1,4), (2,4), (2,3), (2,2), (2,1), (3,1), (4,1), (4,2), (4,3), (4,4)][(0,0), (0,1), (0,2), (0,3), (0,4), (1,4), (2,4), (3,4), (4,4)]




1 0