前提
- 很明显,初始迷宫的路和墙需要定义和保存,(这里用的迷宫用数组存储,用1表示墙,用0表示未走过的路。)
- 需要明确判断下一步朝哪个方向走?(这里的方向是:下->右->上->左,这里将方向用一个二维数组来存储)
- 如何判断下一步是否在迷宫外?这里的处理是在迷宫数组外加“一堵墙”。这堵墙设值为1。
算法过程描述
- 思路:从当前位置获取下一步路径的位置,判断下一步路径的位置是否走过,是不是墙。若始终未找到下一步路径的位置,则返回上一次判断过程,重新选择一个新的路径。如此反复,直至达到出口的位置,输出完整的迷宫路径。
- 问题:如何判断下一步位置是否已经走过或者不是墙?
- 解决方案:
- 第一种解决方案:使用栈来存储迷宫路径位置。当执行判断语句时,扫描全栈,判断这个位置是否已经在栈中。(时间复杂度增加)
- 第二种解决方案:再次定义一个与迷宫(不包含围墙)大小一样的二维数组temp。如果这个位置能够成为迷宫路径,则将temp数组中与这个位置拥有相同坐标的数组元素设为2。(空间复杂度增加)
- 第三种解决方案:在原有的迷宫数组中,将能够成为路径的位置的数组元素设为2(时间复杂度和空间复杂度最优)
- 存储结构
存储下一个路径的方向增量数组
//定义一个数组存储一个格子可以移动的方向增量
//二维数组的行坐标表示x轴的坐标,列坐标表示y轴的坐标
int move[4][4] = {
{1,0},//下面一格
{0,1},//右面一格
{-1,0},//上面一格
{0,-1}//左面一格
};
迷宫初始化定义
#define r 7//迷宫的行数
#define c 8//迷宫的列数
//定义迷宫数组,用0表示这个格子的路,用1表示这个格子是墙,用2表示这个格子走过。
//迷宫外围必须有一堵墙
int M[r+2][c+2] = {
{1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,1,1,1,0,0,1},
{1,0,1,0,0,1,0,0,1,1},
{1,0,1,0,0,0,0,1,1,1},
{1,0,0,1,0,1,0,1,1,1},
{1,1,0,1,1,1,0,1,1,1},
{1,0,0,1,0,0,0,1,1,1},
{1,1,0,0,0,1,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1},
};
一组解与多组解的不同实现
- 一组解:递归方法是有返回值的,用以区分是找到一条完整路径返回上一步操作还是没有找到下一步路径返回上一步操作。若是找到一条路径返回的,则只需要输出当前位置即可,无须,将当前的位置设为0(未走过的路)。
- 多组解:递归函数是无返回值的。因为无论是上述的哪一种情况,都需要将当前的位置设为0(未走过的路)。
- 代码:
//递归实现(求的是一组解)
int Maze_1(int x,int y)
{
if (x == 7 && y == 8)
{
return 1;
}
//找到下一个格子可以进入
for (int i = 0; i < 4; ++i) {
//获取下一格位置
int a = move[i][0] + x;//获取横坐标
int b = move[i][1] + y;//获取纵坐标
//表示路未走过
if (M[a][b] == 0)
{
M[a][b] = 2;//表示路已经走过
//当递归返回的值为1时,表示找到路径
//当递归返回值为0时,表示当前找到的位置不能成为路径,递归返回当上一次,重新寻找位置
tag = Maze_1(a,b);
if (tag)
{
printf("(%d,%d)->",a,b);
return tag;
}
}
}
}
//打印路径
void print()
{
for (int i = 1; i < 8; ++i) {
for (int j = 1; j < 9; ++j) {
if(M[i][j]==2)
{
printf("(%d,%d)->",i,j);
}
}
}
}
void Maze_2(int x ,int y)
{
M[x][y] = 2;//表示当前位置已经走过
if (x == 7 && y == 8)
{
print();
printf("\n");
} else{
//找到下一个格子可以进入
for (int i = 0; i < 4; ++i) {
//获取下一格位置
int a = move[i][0] + x;//获取横坐标
int b = move[i][1] + y;//获取纵坐标
//表示路未走过
if (M[a][b] == 0)
{
Maze_2(a,b);
M[a][b] = 0;
}
}
}
}