回溯算法的经典问题之一:
问题说明:
左上角为入口,右下角为出口。设置小球寻找路径的策略为:下=>右=>上=>左。编写代码,输出小球寻找到的走出迷宫的路径。
解题思路:
迷宫回溯问题的解题主要分为两部分:
-
首先需要在main()中,设置迷宫的形状:
- 通过一个二维数组来实现迷宫的存储
- 对于二维数组中的每一个元素arr[i][j],通过设置该元素的值(0、1、2、3),可以表示该元素对应的迷宫中的位置的情况:
1:该位置存在挡板,不可以走;
2:该位置已经走过(也不可以走,如果继续走的话,会形成回路,出不来迷宫);
3:该位置已经周国,但是走不通(其实,也是说该位置走不通,不过与“1”不同的是:该位置是经过回溯之后形成的结果,并不是直接有挡板在)
0:该位置可以尝试着走 -
需要一个实现 递归-回溯 的方法:
public boolean setWay(形参)- 该方法的形参:map[][],i,j
含义分别为:
1、map[][],表示存储迷宫路径及其实际情况的数组,在实现递归调用的所有栈空间中, 该二维数组 作为一个共享数据:即,所有的尝试操作,都是在这一个数组上进行的
2、i:记录迷宫中所要尝试的位置的横坐标
3、j:记录迷宫中所要尝试的位置的纵坐标
------>默认的是:该迷宫的最外层是一层“1”包围着,不会出现二维数组的下标越界的情况- 该方法中,需要设置走迷宫的尝试顺序(其实,就是设置一下,在迷宫中到的某个位置,尝试下一步所走的方向 的顺序)
这里设置的顺序为:下=>右=>上=>左 - 该方法中,因为要实现 递归-回溯,所以,需要设置递归的终止条件,以及进行递归调用的语句:
①递归的终止条件:if(map[6][5]==2)
即,迷宫出口前的那步,已经走完了
②递归调用的语句:相对于上面的部分,是else{}中的内容
1>如果该位置,可以走:
map[i][j]==0//因为0表示该位置可以尝试:
---->因为涉及到回溯,最终才能确定要走的路径,所以应该先设置该位置map[i][j]=2;//即,该位置已经走过
主要分为以下几个模块:
1、先尝试向 “下” 走:
if(setWay(map,i+1,j)
如果返回的值为true,则表示该位置可以向下走,也返回true到上一级(返回的是上一级的if中的递归语句处);
如果返回的是false,则尝试else(在该点向右=>上=>左)
2、尝试向 “右” 走:
if(setWay(map,i,j+1)
如果返回的值为true,则表示该位置可以向右走,也返回true到上一级(返回的是上一级的if中的递归语句处);
如果返回的是false,则尝试else(在该点向上=>左)
3、尝试向 “上” 走:
if(setWay(map,i-1,j)
如果返回的值为true,则表示该位置可以向上走,也返回true到上一级(返回的是上一级的if中的递归语句处);
如果返回的是false,则尝试else(在该点向左)
4、尝试向 “左” 走:
if(setWay(map,i,j-1)
如果返回的值为true,则表示该位置可以向上走,也返回true到上一级(返回的是上一级的if中的递归语句处);
如果返回的是false,则尝试else
5、else:
是在该点处,尝试完了一遍下=>右=>上=>左的方向之后,发现:四个方向都走不通,表明走到这个位置,遇见了死路口
------>
实现回溯功能:将该位置对应的二维数组中的元素,值置为3:表明该位置处走不通
map[i][j]=3;
并且,return false:
向调用处表明:该方向尝试失败,需要尝试其他方向2>该位置如果不可走(对应map[i][j]==1或2或3):
此时,应该直接return false,表示该位置不可以走,需要尝试下一个方向的位置 - 该方法的形参:map[][],i,j
代码实现:
public class MiGong {
public static void main(String[] args) {
//该二维数组,存储迷宫中的位置的状态
int[][] map = new int[8][7];
/*
* 设置迷宫中的挡板:
*/
//先设置底部和顶部的第一行均为挡板:行坐标是定值,列坐标在改变
for (int i = 0; i < 7; i++) {
map[0][i] = 1;
map[7][i] = 1;
}
//设置最左和最右的第一列均为挡板:行坐标在变,列坐标不变
for (int i = 0; i < 8; i++) {
map[i][0] = 1;
map[i][6] = 1;
}
//另外还有两个小挡板
map[2][1] = 1;
map[2][2] = 1;
System.out.println("迷宫的模样为:");
for (int i = 0; i < 8; i++) {//行
for (int j = 0; j < 7; j++) {//列
System.out.print(map[i][j] + " ");
}
System.out.println();
}
setWay(map,1,1);//从迷宫入口处,开始调用递归方法
System.out.println("走出迷宫对应的路径为");
for (int i = 0; i < 8; i++) {//行
for (int j = 0; j < 7; j++) {//列
System.out.print(map[i][j] + " ");
}
System.out.println();
}
}
public static boolean setWay(int[][] map,int i,int j) {
/*
* 先判断是否已经到达迷宫的出口处
*/
if(map[6][5] == 2) {
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 {
/*
* 此时,已经将4个方向都尝试了一遍,并且没有一个方向可以走通(最终到达:迷宫出口)
*/
map[i][j] = 3;//先进行回溯操作
return false;
}
}else {
/*
* 该位置的标记为:1或2或3
* 没有进行尝试的必要,
* ----此时,已经做过的路对应的是一条死路
*/
return false;
}
}
}
}
十倍努力,做突出一个!
继续加油!!!