持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情
1、把迷宫抽象成数组
我们用二维数组来表达一个mn大小的迷宫,0表示行走的路,1表示墙,这样我们就可以用以(x,y)坐标来表示我们当前所在的为,在用一个变量move表示行动方向。但是,对于内部点坐标,会有四个方向,而对于数组边界的点只有两个或三个可以移动的方向,我们在地图外围加一个圈1,构建一个(m+2)(n+2)大小的数组,就可以实现m*n大小的地图上每一个坐标点都有四个移动方向。
int maze[m + 2][n + 2] = {//设计迷宫,0表示可以路,1表示强。改图把出口设置在右下墙角。
{1,1,1,1,1,1,1,1,1,1}
,{1,0,1,1,1,0,1,1,1,1}
,{1,0,0,0,0,1,1,1,1,1}
,{1,0,1,0,0,0,0,0,1,1}
,{1,0,1,1,1,0,0,1,1,1}
,{1,1,0,0,1,1,0,0,0,1}
,{1,0,1,1,0,0,1,1,0,1}
,{1,1,1,1,1,1,1,1,1,1} };//(1,1)为入口,(6,8)为出口,
2、求解思路——回溯法
我们可以用一个长度为四的结构体数组表示方向:
typedef struct {
int x, y;
}item;
item move[4] = { {0,1},{1,0},{0,-1},{-1,0} };
对于我们所在点(x,y),可能移动的位置一共就这四个(x,y+1)、(x+1,y)、(x,y-1)、(x-1,y),对每四个方向的点进行数值0或1的判断,就是到该点是否可行走。在这里,我们设置了默认先从(x,y+1)方向先开始判断(即有右向)。如果为1,说明该方向为墙,不能行走;如果为1,说明可以行走,则将该点作为新点坐标(x,y),将原本所在的点压入栈内,且标记为-1;如果为-1,表示该坐标点曾经来过。比如说,当我们走到(3,5)点时,判断出右方(3,6)点可以行走,便移动到了(3,6),继而走到(3,7)点发现此路不通,所以原路返回到(3,6)点,因为已经知道(3,6)来过,且右方向不能到达出口,便继续对下一个方向进行判断,而不是从默认的右边顺时针依次判断。,否则会进入死循环。
3、代码详解
结构体设置: 每一坐标点都有x,y。d(1,2,3,4)表示四个方向,若四个方向都没有0,就要原路返回到上一个岔路口。
typedef struct {
int x, y, d;
}DataType;//点的坐标结构体,连接起来就是行动路线了。
//定义结构体
typedef struct
{
DataType data[MAXSIZE];//行动路线
int top;
}SeqStack, *PSeqStack;
求解算法:
int mazepath(int maze[][n + 2], item move[], int x0, int y0)//(x0,y0)为迷宫入口
{
PSeqStack S;
DataType temp;//入口
int x = 0, y = 0, d = 0, i = 0, j = 0;
temp.x = x0; temp.y = y0; temp.d = -1;
S = Init_SeStack();
if (!S) {
printf("栈初始化失败!");
return 0;
}
Push_SeqStack(S, temp);//迷宫入口入栈
while (!Empty_SeqStack(S))
{
Pop_SeqStack(S, &temp);
x = temp.x; y = temp.y; d = temp.d + 1;
while (d < 4)//对该坐标点的四个方向进行循环判断(从右侧开始顺时针)
{
i = x + move[d].x; j = y + move[d].y;//(i,j)为要判断的点的坐标
if (maze[i][j] == 0) //如果是零,表示可以通过,则将该点压入栈内。
{
temp.x = x;
temp.d = d;
temp.y = y;
Push_SeqStack(S, temp);//入栈
x = i; y = j; maze[x][y] = -1;//把走过的路全部标记为-1,原路返回时不用再判断了。
if (x == m && y == n)//m,n是最边界的墙,如果点的右边和下面都是墙,表示该点为出口。
{
//遇到出口,将栈中元素全部出栈打印,就可以得到迷宫的行动路线。
temp.x = x; temp.y = y;
while (!Empty_SeqStack(S))
{
Pop_SeqStack(S, &temp);
printf("(%d,%d)\n", temp.x, temp.y);
}
Destroy_SeqStack(&S);//销毁栈
return 1;//运行结束,成功找到出口!!
}
//如果不是出口,则此路不通,原路返回到上一个岔路口。
else
d = 0;
}
else//如果maze[i][j] != 0,表示该方向不能走,d++,尝试下一个方向。
{
d++;
}
}
}
Destroy_SeqStack(&S);
return 0;
}
4、运行结果
从(1,1)到(6,8)为正确的行动路线。