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

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("√,");
				else
					System.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("√,");
				else
					System.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)]




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值