回溯法求解迷宫问题,使用了堆栈数据结构。
源码下载地址:使用DEV-C 5.11编译
定义一个结构,用来存储迷宫的坐标数据
typedef struct
{
int x; /* 行值 */
int y; /* 列值 */
}PosType;
规定迷宫的最大范围是25*25
#define MAXLENGTH 25
定义迷宫数据类型,就是整型二维数组,起个别名叫 MazeType
typedef int MazeType[MAXLENGTH][MAXLENGTH];
然后,给定迷宫尺寸,包括围墙,例如10*10,那么程序将生成一个空的围墙迷宫轮廓,用0表示墙,其它地方表示可通过,用1表示
//下面的语句是把迷宫围起来
for(i=0;i<x;i++) /* 定义周边值为 0(同墙) */
{
m[0][i]=0; /* 行周边 */
m[x-1][i]=0;
}
for(j=1;j<y-1;j++)
{
m[j][0]=0; /* 列周边 */
m[j][y-1]=0;
}
for(i=1;i<x-1;i++)
for(j=1;j<y-1;j++)
m[i][j]=1; /* 定义通道初值为1 */
此时迷宫中的数据如下:
四周是围墙,中间有数字1的部分是可以通过的部分。
x是行,y是列
坐标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
2 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
3 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
4 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
5 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
6 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
7 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
8 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
接着程序要求提供迷宫中的墙的位置的数据,可以定义一个数组,用坐标说明墙的位置:
PosType wall[18]={\
{1,3},{1,7},{2,3},{2,7},{3,5},{3,6},\
{4,2},{4,3},{4,4},{5,4},{6,2},{6,6},\
{7,2},{7,3},{7,4},{7,6},{7,7},{8,1}\
};
之后,程序生成这样的迷宫图,迷宫中值为0的地方就表示墙。值为1的地方是可以通过的地方。
x是行,y是列
坐标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | 0 |
2 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | 0 |
3 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | 0 |
4 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 |
5 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 |
6 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 0 |
7 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
8 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
接着,程序要求给出起始位置坐标,这里是1,1,和终止位置坐标8,8。
begin.x=1; begin.y=1;
end.x=8; end.y=8;
然后,程序开始探索迷宫,每进入一个坐标点位,都判断一下这里是否可以通过,也就是坐标点位上的值是否为1。
if(Pass(curpos))
如果可以通过,坐标入栈,并在这一坐标处记录走过的步数。
FootPrint(curpos); //在迷宫当前坐标处留下足迹,就是在迷宫单元中记录走到第几步了
//下面的步骤将 e 堆栈元素压入堆栈
e.ord=curstep; //记录足迹编号,就是走第几步了
e.seat.x=curpos.x; //记录迷宫坐标
e.seat.y=curpos.y;
e.di=0; //记录方向,0,1,2,3分别代表 东南西北
Push(&S,e); //S是堆栈变量,e是堆栈元素
接着按东南西北的顺序试图走下一步,如果可以通过,还是坐标入栈,记录步数。
curpos=NextPos(curpos,e.di);
这个堆栈元素e.di就是用来记录方向的,规定东:0,南:1,西:2,北:3
如果不能通过,则进行弹栈操作,退回到上一可以通过的步子处,继续按照东南西北的顺序探索下一步。如此循环往复,直到走出迷宫。
Pop(&S,&e); /* 退栈到前一位置 */
curstep--;
while(e.di==3 && !StackEmpty(S)) /* 前一位置处于最后一个方向(北) */
{
MarkPrint(e.seat); /* 留下不能通过的标记(-1) */
Pop(&S,&e); /* 退回一步 */
curstep--;
}
if(e.di<3) /* 没到最后一个方向(北) */
{
e.di++; /* 换下一个方向探索 */
Push(&S,e);
curstep++;
curpos=NextPos(e.seat,e.di); /* 设定当前位置是该新方向上的相邻块 */
}
还有一种情况是,当走到某一步时候,四个方向上都无法通过,这时,需要在这一坐标处标记-1,表示探索过,没有通路。
迷宫中的值有这几种情况:
a.可以通过的坐标点位用1表示
b.如果值>1,表示记录着步数,也就是这里已经走过了,
c.如果是0,表示这里是墙,
d.如果是-1,表示这里走过且不通。
最后得到的一条迷宫路径:-1表示走过,但是不通,又往回退的情况。
走迷宫过程的视频演示: