递归解决迷宫问题
什么是递归?
递归,就是在运行的过程中调用自己。
构成递归需具备的条件:
- 子问题须与原始问题为同样的事,且更为简单;
- 不能无限制地调用本身,须有个出口,化简为非递归状况处理。
解决什么问题?
这是一个迷宫,编写一个程序,使其找到一条从起点通往终点路,怎么去实现呢?
实现前提说明
如上图,是一个8*7的表格,在里面找路,我们首先得构建出这个迷宫。
说明:
1、定义一个二维数组map来表示这个迷宫。
2、i,j表示从地图什么地方开始出发。
3、如果能走到map[6][5]位置,则说明通路找到。
4、约定:当map[i][j]为0表示该点没有走过,当为1表示墙,2表示通路可以走,3表示该点已经走过,但走不通。
5、在走迷宫时,需要确定一个策略,走路顺序为:下->右->上->左,如果该点下右上左都走不通,在回溯。
问题解决
我们首先构建迷宫二维数组
int[][] map = new int[8][7];
//设置围墙,1表示墙
for (int i = 0; i < map.length; i++) {
map[i][0] = 1;
map[i][map[0].length - 1] = 1;
}
for (int i = 0; i < map[0].length; i++) {
map[0][i] = 1;
map[map.length - 1][i] = 1;
}
//设置挡板,1表示墙
map[6][2] = 1;
map[6][4] = 1;
我们输出看一下:
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 1 0 1 0 1
1 1 1 1 1 1 1
我们定义一个递归方法setWay,参数是一个二维数组和当前所在位置的i,j。
1、我们首先判断现在所处的位置是否是终点map[6][5],是就返回true。
2、如果不为终点,我们就进行我们的策略走法:
2.1、如果当前这个点为0,证明还没有走,首先将这个点赋值为2,然后进行递归,把位置向下移动一位setWay(map, i + 1, j),i+1就是向下走,j+1就是向右走,i-1就是向上走,j-1就是向左走,我们,向下移动发现这个点不为0,可能是1、2、3,返回false,然后回溯到上一次调用,然后开始向右走,还走不通向上向左,都走不通把这个点设置为3,回溯到上一个点,开始向右走,就这样直到找到出口,或者没有出口全图走一遍。
代码实现
public static boolean setWay(int[][] map, int i, int j) {
if (map[6][5] == 2) {//通路已经找到,直接返回true
return true;
} else {
if (map[i][j] == 0) {//如果当前这个点还没走过
//按照策略 下->右->上->左 走
map[i][j] = 2;
if (setWay(map, i + 1, j)) {//向下走
return true;
} else if (setWay(map, i, j + 1)) {//向右走
return true;
} else if (setWay(map, i - 1, j)) {//向上走
return true;
} else if (setWay(map, i, j - 1)) {//向左走
return true;
} else {//都走不了,证明是死路,标注为3
map[i][j] = 3;
return false;
}
} else {//如果map[i][j] !=0,可能是1、2、3
return false;
}
}
}
测试结果
找到路的状态:
1 1 1 1 1 1 1
1 2 0 0 0 0 1
1 2 0 0 0 0 1
1 2 0 0 0 0 1
1 2 0 0 0 0 1
1 2 2 2 2 2 1
1 3 1 3 1 2 1
1 1 1 1 1 1 1
实话说,递归并不好理解,大家可以画一个图,一步一步跟着代码走一遍就懂了。
全部代码:
public class MiGong {
public static void main(String[] args) {
int[][] map = new int[8][7];
//设置围墙,1表示墙
for (int i = 0; i < map.length; i++) {
map[i][0] = 1;
map[i][map[0].length - 1] = 1;
}
for (int i = 0; i < map[0].length; i++) {
map[0][i] = 1;
map[map.length - 1][i] = 1;
}
//设置挡板,1表示墙
map[6][2] = 1;
map[6][4] = 1;
// map[6][4] = 1;
// map[5][4] = 1;
// map[5][5] = 1;
//输出地图
System.out.println("地图原始状态:");
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
System.out.print(map[i][j] + " ");
}
System.out.println();
}
if (setWay(map, 1, 1)) {
//输出地图
System.out.println("找到路的状态:");
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
System.out.print(map[i][j] + " ");
}
System.out.println();
}
} else {
//输出地图
System.out.println("找不到路的状态:");
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
System.out.print(map[i][j] + " ");
}
System.out.println();
}
System.out.println("找不到路哦!");
}
}
/**
* 使用递归回溯来给小球找路
* 说明:
* 1.map 表示地图
* 2.i,j 表示从地图什么地方开始出发
* 3.如果小球能到map[6][5]位置,则说明通路找到
* 4.约定:当map[i][j]为0表示该点没有走过 当为1表示墙,2表示通路可以走,3表示该点已经走过,但是走不通
* 5.在走迷宫时,需要确定一个策略,下->右->上->左,如果该点走不通,在回溯
*
* @param map 表示地图
* @param i 从哪个位置开始找
* @param j
* @return 如果找到通路返回true,否则返回false
*/
public static boolean setWay(int[][] map, int i, int j) {
if (map[6][5] == 2) {//通路已经找到,直接返回true
return true;
} else {
if (map[i][j] == 0) {//如果当前这个点还没走过
//按照策略 下->右->上->左 走
map[i][j] = 2;
if (setWay(map, i + 1, j)) {//向下走
return true;
} else if (setWay(map, i, j + 1)) {//向右走
return true;
} else if (setWay(map, i - 1, j)) {//向上走
return true;
} else if (setWay(map, i, j - 1)) {//向左走
return true;
} else {//都走不了,证明是死路,标注为3
map[i][j] = 3;
return false;
}
} else {//如果map[i][j] !=0,可能是1、2、3
return false;
}
}
}
}