一、需求
经典的迷宫问题,就是:一颗小球通过移动格子,最终要走到目的地。移动格子到目的地的这段路径就是最终的结果。但是格子有障碍物,移动的过程中遇到障碍物的话是不能继续移动的,需要换其他格子去走。如下图:
二、coding
1、代码实现格子
思路:
首先这是一个8*7的网格,用1代表障碍物。从图中可以分析出
1.上下左右四面都是障碍物。也就是:第1行的第1-7列都是障碍物;第7行的第1-7列都是障碍物;第1列的第1-8行都是障碍物;第6列的第1-8行都是障碍物。
2.第四行的第一二两列是障碍物,也就是map[3][1] = 1; map[3][2] = 1;
public class MiGong {
public static void main(String[] args) {
// 先创建一个二维数组,模拟迷宫
// 地图 8行7列
int[][] map = new int[8][7];
// 使用1表示障碍物
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[3][1] = 1;
map[3][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();
}
}
}
地图的情况:
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 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 1 1 1 1 1 1
2、思路分析
1、使用递归算法来给小球找路
2、定义二维数组,来画出墙和障碍物,障碍物用数字1表示
3、定义好起始位置也目的地。起始位置:【1, 1】目的地:【6,5】
4、定义数字0表示该点没走过,数字1表示障碍物;数字2表示该路可以走通;数字3表示已经走过该路,但是该点走不通
5、定义策略:先走下面,下面走不通再走右边,右边走不通就走上面,上面走不通就走左边。下->右->上->左的顺序。
3、思路图解
若按照下->右->上->左的顺序走,那最终应该是这样的结果
4、完整代码
public class MiGong {
public static void main(String[] args) {
// 先创建一个二维数组,模拟迷宫
// 地图 8行7列
int[][] map = new int[8][7];
// 使用1表示障碍物
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[3][1] = 1;
map[3][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();
}
}
/**
* 使用递归回溯来给小球找路
*
* @param map 表示地图
* @param i 从哪个位置开始找
* @param j
* @return 如果找到通路,就返回true,否则false
*/
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;
}
// 向右走
if (setWay(map, i, j + 1)) {
return true;
}
// 向上走
if (setWay(map, i - 1, j)) {
return true;
}
// 向左走
if (setWay(map, i, j - 1)) {
return true;
}
// 说明该点是走不通的,是死路一条
map[i][j] = 3;
return false;
} else { // 如果map[i][j] != 0,那可能是1,2,3,那就没必要再走这条路了。即使是2也不要走了,因为2代表这条路已经走过了
return false;
}
}
}
}
地图的情况:
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 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 1 1 1 1 1 1
小球走过,并表识过的地图的情况
1 1 1 1 1 1 1
1 2 0 0 0 0 1
1 2 2 2 0 0 1
1 1 1 2 0 0 1
1 0 0 2 0 0 1
1 0 0 2 0 0 1
1 0 0 2 2 2 1
1 1 1 1 1 1 1
5、换个策略
上面案例是下->右->上->左的顺序。现在换成上->右->下->左的顺序来玩一把。正常的路径应该是如下:
package com.chentongwei.struct.recursion;
/**
* Description:
*
* @author TongWei.Chen 2019-12-25 15:05:20
*/
public class MiGong {
public static void main(String[] args) {
// 先创建一个二维数组,模拟迷宫
// 地图 8行7列
int[][] map = new int[8][7];
// 使用1表示障碍物
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[3][1] = 1;
map[3][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();
}
// 使用递归回溯给小球找路
setWay2(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();
}
}
/**
* 修改找路的策略,改成 上->右->下->左
*
* @param map:地图
* @param i:从i、j出发开始找
* @param j
* @return
*/
public static boolean setWay2(int[][] map, int i, int j) {
// 通路已经找到了
if (map[6][5] == 2) {
return true;
} else {
// 若当前这个点还没有走过
if (map[i][j] == 0) {
// 按照策略走:上->右->下->左
// 假定这个点是可以走通的
map[i][j] = 2;
// 向上走
if (setWay2(map, i - 1, j)) {
return true;
}
// 向右走
if (setWay2(map, i, j + 1)) {
return true;
}
// 向下走
if (setWay2(map, i + 1, j)) {
return true;
}
// 向左走
if (setWay2(map, i, j - 1)) {
return true;
}
// 说明该点是走不通的,是死路一条
map[i][j] = 3;
return false;
} else { // 如果map[i][j] != 0,那可能是1,2,3,那就没必要再走这条路了。即使是2也不要走了,因为2代表这条路已经走过了
return false;
}
}
}
}
地图的情况:
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 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 1 1 1 1 1 1
小球走过,并表识过的地图的情况
1 1 1 1 1 1 1
1 2 2 2 2 2 1
1 0 0 0 0 2 1
1 1 1 0 0 2 1
1 0 0 0 0 2 1
1 0 0 0 0 2 1
1 0 0 0 0 2 1
1 1 1 1 1 1 1
三、扩展
上述的策略(走路顺序)可以自定义,随意就好。如何找到最短路径的问题可以简单粗暴lowb的方法就是:
将所有的策略都走一遍,然后存到数组里,最后遍历数组中2(走通的代表)数量最少的那条路径。