在迷宫中,从入口到出口往往有一条或者多条最短路径。可以使用队列来求解迷宫的最短路径,使用队列时,搜索路径是一层一层向前推进,第一次找到出口是搜索的层数最少,这种搜索方法与广度优先算法类似。
使用队列Qu记录走过的方块,该队列的结构如下:
struct{
int i; //方块的行号
int j; //方块的列号
int pre; //前一方块在队列中的下标
}Qu[MaxSize]; //定义顺序队列
int front=0,rear=0; //定义队头和队尾指针并置初值为0
这里使用的队列Qu不是环形队列,为什么不采用环形队列呢?因为元素出队后,还要利用它输出路径,所以不将出队元素真正地删除。
搜索从(x1,y1)到(x2,y2)路径的过程是:首先将(x1,y1)入队,在队列Qu不为空时循环,出队一次(由于不是环形队列,该出队元素仍在队列中),称该出队的方块为当前方块,front为该方块在Qu中的下标。
如果当前方块为出口,则输出路径并结束。否则,按顺时针方向找出当前方块的4个方位中可走的相邻方块(对应的mg数组为0),将这些可能的相邻方块均插入到队列Qu中,其pre设置为搜索路径中上一个方块在Qu中的下标值,也就是当前方块的front值,并将相邻方块对应的mg数组值置为-1,以避免重复搜索。如果队列为空,表示未找到出口,即不存在路径。
如图(1)所示的迷宫,求它从起点到终点所有的最短路径。
代码如下:
//migong.cpp
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 100
#define M1 6 //迷宫的最大行数
#define N1 6 //迷宫的最大列数
struct {
int i; //方块的行号
int j; //方块的列号
int pre; //前一方块在队列中的下标
}Qu[MaxSize]; //定义顺序队列
int front = 0, rear = 0; //定义队头和队尾指针并置初值为0
int mg1[M1][N1] = { //1: 代表墙,0: 代表通道
{ 1,1,1,1,1,1 },
{ 1,0,0,0,1,1 },
{ 1,0,1,0,0,1 },
{ 1,0,0,0,1,1 },
{ 1,0,0,0,0,1 },
{ 1,1,1,1,1,1 }
};
int minlen = 0; //最短路径长度
int num = 1; //路径计数
//从队列中输出路径
void print1(int front) {
int k = front, j;
int ns = 0;
do
{
j = k;
k = Qu[k].pre;
ns++;
} while (k != -1);
if (num == 1) minlen = ns;
if (ns == minlen)
{
ns = 0;
k = front;
printf(" 第%d条最短路径(反向输出): \n", num++);
do
{
j = k;
printf("\t(%d,%d)", Qu[k].i, Qu[k].j);
k = Qu[k].pre;
if (++ns % 5 == 0) printf("\n");
} while (k != -1);
printf("\n");
}
}
//搜索路径为: (x1,y1) --> (x2,y2)
void mgpath1(int x1, int y1, int x2, int y2) {
int i, j, find = 0, di, k;
rear++;
Qu[rear].i = x1; Qu[rear].j = y1;
Qu[rear].pre = -1; //(x1,y1)入队
while (front <= rear)
{
front++;
for (di = 0; di < 3; di++)
{
switch (di) {
case 0: i = Qu[front].i - 1; j = Qu[front].j;
break;
case 1: i = Qu[front].i; j = Qu[front].j + 1;
break;
case 2: i = Qu[front].i + 1; j = Qu[front].j;
break;
case 3: i = Qu[front].i; j = Qu[front].j - 1;
break;
}
//方块(i,j)不越界,且可走
if (i > 0 && j > 0 && mg1[i][j] == 0
&& (i != Qu[Qu[front].pre].i || j != Qu[Qu[front].pre].j))
{
rear++;
Qu[rear].i = i; Qu[rear].j = j;
Qu[rear].pre = front; //指向路径中上一个方块的下标
}
}
}
for (k = 0; k <= rear; k++)
{
if (Qu[k].i == x2 && Qu[k].j == y2) //找到了出口,输出路径
{
find = 1;
print1(k);
}
}
if (!find)
printf("不存在路径!\n");
}
int main()
{
printf("所有迷宫([1,1]->[4,4])最短路径\n");
mgpath1(1, 1, M1 - 2, N1 - 2); //(1,1)->(M1-2,N1-2)
system("pause"); //窗口暂停
return 0;
}
效果如下: