迷宫回溯问题

回溯算法的经典问题之一:

问题说明:

迷宫的简略示意图
左上角为入口,右下角为出口。设置小球寻找路径的策略为:下=>右=>上=>左。编写代码,输出小球寻找到的走出迷宫的路径。

解题思路:

迷宫回溯问题的解题主要分为两部分:

  1. 首先需要在main()中,设置迷宫的形状:

    • 通过一个二维数组来实现迷宫的存储
    • 对于二维数组中的每一个元素arr[i][j],通过设置该元素的值(0、1、2、3),可以表示该元素对应的迷宫中的位置的情况:

    1:该位置存在挡板,不可以走;
    2:该位置已经走过(也不可以走,如果继续走的话,会形成回路,出不来迷宫);
    3:该位置已经周国,但是走不通(其实,也是说该位置走不通,不过与“1”不同的是:该位置是经过回溯之后形成的结果,并不是直接有挡板在)
    0:该位置可以尝试着走

  2. 需要一个实现 递归-回溯 的方法:
    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,表示该位置不可以走,需要尝试下一个方向的位置

代码实现:
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;
			}
		}
		
		
	}
	
}

十倍努力,做突出一个!
继续加油!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值