迷宫求解(使用队列

245 篇文章 8 订阅
52 篇文章 2 订阅

在迷宫中,从入口到出口往往有一条或者多条最短路径。可以使用队列来求解迷宫的最短路径,使用队列时,搜索路径是一层一层向前推进,第一次找到出口是搜索的层数最少,这种搜索方法与广度优先算法类似。
  使用队列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;
}

效果如下:

图(2) 从起点到终点的最短路径有:4条(反向输出)

  • 6
    点赞
  • 83
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sanqima

一键三连,多多益善

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值