【c++】广度优先求解迷宫问题最短路径

学习 2018-10-13 16:262160阅读 · 48喜欢 · 3评论

卍卍子非鱼卍卍

粉丝:1094文章:14

关注

求解迷宫问题有两种基本思路,深度优先与广度优先。这次介绍其中一种:广度优先

在此之前不妨先介绍一下什么是深度优先,什么是广度优先

想想一下自己现在正处于迷宫之中,面前有几条岔路(该迷宫不止一条正确路径)

深度优先:

    你觉得只要能出去就行,于是决定一条一条路去试,但是瞎jb试容易把自己搞糊涂,所以你制定了一条规则,一直沿着右手边那条路走(当然如果你觉得用左手更舒服也可以选择左边),直到遇见死胡同,拐回最近的岔路口,重复这样的行为,当然,已经走过的路就不必再走一遍了。这样你很开心,因为你可以遍历所有的岔路而不必担心忘记哪条路走过哪条路没走。这样一来,你迟早会找到出口,但这样的缺点是什么呢,当你站在出口处回首迷宫,你会发现,因为一味的沿右手走,你很可能因此走了很多弯路,换句话说,这并不是最短的路线。

广度优先:

  你作为一个强迫症,决定一定要找到最短的出迷宫的路线,所以站在岔路口的你选择先将所有岔路放入“备选项”。而你走过的路是不能再经过备选项的,因为显然如果那样的话直接走备选项岂不是少走很多路?举个例子

这是一个迷宫,入口在1,出口在3,如果你选择深度优先并且很不幸的选择了左手,那么你的路线是1->2->4->3,你走了4个格子终于找到了出口

但当你选择广度优先呢?

当你还在1的时候就将2和3放入了备选项,然后你走到了2,这时候只有4能进到你的备选项,但当你走到4的时候发现:嗯?3已经在备选项中了,那我干嘛不直接从1走到3?于是,最优解诞生了(鼓掌)。

但是广度优先也有缺点,其中之一就是因为要记忆很多备选项,自然占用的脑容量就要很多。

所以,选择深度优先还是广度优先还是需要根据特定情况进行抉择。

废话了这么多来说一下算法设计思路

这是我们的迷宫

我们需要一个队列存储所有备选项

队列中充斥着结构体Box,Box即是迷宫中的一个个单元格,Box中有一个int型pre,用来记录该Box的来时的Box在该队列中的位置,比如对于线路Box1->Box2来说,Box2中存储了Box1在队列中的位置

入口方块进队,队列不为空时循环

循环体内:

    出队一个方块e,找e周围所有可以走的方块,假设有e1,e2,将它们两个进队,pre均设置为front

    直到e的坐标与出口坐标相等,即为找到了出口,通过pre逆向查找至入口,得出最短路径,正向打印.

源码:

头文件Queue.h:

#pragma once

#define MaxSize 100

typedef struct

{

    int i, j;    //方块在地图中的位置

    int pre; //该路径中上一个方块在队列中的下标

}Box;    //方块类型

typedef struct

{

    Box data[MaxSize];

    int front, rear;

}Queue;      //用于存放路径的队列

void InitQueue(Queue *& q)

{

    q = (Queue *)malloc(sizeof(Queue));

    q->front = q->rear = -1;

}

void DestroyQueue(Queue *&q)

{

    free(q);

}

bool QueueEmpty(Queue *q)

{

    return (q->front == q->rear);

}

bool enQueue(Queue *& q, Box e)

{

    if (q->rear == MaxSize - 1)

         return false;

    q->rear++;

    q->data[q->rear] = e;

    return true;

}

bool deQueue(Queue *& q, Box & e)

{

    if (q->rear == q->front)

         return false;

    q->front++;

    e = q->data[q->front];

    return true;

}

cpp:

#include <iostream>

#include "Queue.h"

#define M 8

#define N 8

using namespace std;

int map[M + 2][N + 2] = {  //地图,1为不可走,0为可走

{1,1,1,1,1,1,1,1,1,1},{1,0,0,1,0,0,0,1,0,1},{1,0,0,1,0,0,0,1,0,1},{1,0,0,0,0,1,1,0,0,1},{1,0,1,1,1,0,0,0,0,1},

{1,0,0,0,1,0,0,0,0,1},{1,0,1,0,0,0,1,0,0,1},{1,0,1,1,1,0,1,1,0,1},{1,1,0,0,0,0,0,0,0,1},{1,1,1,1,1,1,1,1,1,1}

};

void ShowPath(Queue *qu, int front)     //输出正确路径

{

    int p = front, p0;

    do

    {

         p0 = p;

         p = qu->data[p].pre;

         qu->data[p0].pre = -1;//将正确路径的pre记为-1用以标记

    } while (p != 0); //利用循环反向找出正确路经

    cout << "最短路径:" << endl;

    for (int k = 0; k < MaxSize; k++)

    {

         if (qu->data[k].pre == -1)

         {

             cout << "(" << qu->data[k].i << "," << qu->data[k].j << ")";

             cout << "->";

         }

    }

}

bool Path(int x0, int y0, int x, int y) //广度优先找最优解

{

    int i, j, i0, j0; //i,j存储当前方块位置,i0,j0存储找到新路径的位置

    Box e;   //当前方块

    Queue * qu;

    InitQueue(qu);

    e.i = x0;    //设置起点位置

    e.j = y0;

    e.pre = -1;  //起点pre设置为-1;

    enQueue(qu, e);   //起点入队

    map[x0][y0] = -1; //走过的点记为-1,表示不可再走

    while (!QueueEmpty(qu))        //队非空时循环

    {

         deQueue(qu, e);       //出队,用e存储

         i = e.i; //记录该点坐标

         j = e.j;

         if (i == x && j == y)

         {

             ShowPath(qu, qu->front);  //打印路径

             DestroyQueue(qu);

             return true;

         }

         for (int circle = 0; circle < 4; circle++)  //遍历周围的方块,若方块可走就将其进队

         {

             switch (circle)   //遍历顺序为:上,右,下,左

             {

             case 0:

                  i0 = i - 1;

                  j0 = j;

                  break;

             case 1:

                  i0 = i;

                  j0 = j + 1;

                  break;

             case 2:

                  i0 = i + 1;

                  j0 = j;

                  break;

             case 3:

                  i0 = i;

                  j0 = j - 1;

                  break;

             }

             if (map[i0][j0] == 0) //移动至新位置

             {

                  e.i = i0;

                  e.j = j0;

                  e.pre = qu->front;    //用pre记录队列的数据下标

                  enQueue(qu, e);

                  map[i0][j0] = -1;

             }

         }

    }

    DestroyQueue(qu); //若队为空,说明遍历所有可以到达的方块后依旧找不到出口,即为无解

    return false;

}

int main()

{

    if (!Path(1, 1, 8, 8))

         cout << "迷宫无正确路径";

    return 0;

}

结果:

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的用栈求解迷宫问题所有路径及最短路径C++程序: ```c++ #include <iostream> #include <stack> using namespace std; const int N = 5; // 迷宫大小为5*5 int maze[N][N] = { {0, 0, 1, 0, 1}, {0, 0, 1, 0, 0}, {0, 0, 0, 1, 0}, {1, 1, 0, 0, 0}, {0, 0, 1, 0, 0} }; // 迷宫地图,0表示通路,1表示障碍物 struct Node { int x, y, step; Node(int _x, int _y, int _step) : x(_x), y(_y), step(_step) {} // 定义一个结构体表示节点的坐标和步数 }; stack<Node> s; // 定义一个栈存储节点 void printPath(stack<Node> path) { // 打印路径 stack<Node> tmp; while (!path.empty()) { tmp.push(path.top()); path.pop(); } while (!tmp.empty()) { cout << "(" << tmp.top().x << ", " << tmp.top().y << ") "; tmp.pop(); } cout << endl; } void findPath() { int dx[4] = {0, 1, 0, -1}; // 定义四个方向 int dy[4] = {1, 0, -1, 0}; s.push(Node(0, 0, 0)); // 将起点压入栈中 while (!s.empty()) { Node cur = s.top(); s.pop(); if (cur.x == N-1 && cur.y == N-1) { // 到达终点 printPath(s); // 打印路径 cout << "步数为:" << cur.step << endl; // 打印步数 return; } for (int i = 0; i < 4; i++) { // 遍历四个方向 int nx = cur.x + dx[i]; int ny = cur.y + dy[i]; if (nx >= 0 && nx < N && ny >= 0 && ny < N && maze[nx][ny] == 0) { // 判断是否越界和是否是通路 s.push(Node(nx, ny, cur.step+1)); // 将新节点压入栈中 maze[nx][ny] = 1; // 标记为已经走过 } } } } int main() { findPath(); return 0; } ``` 代码中使用了一个栈来存储节点,每次从栈中取出一个节点,判断它是否到达终点,如果到达终点则输出路径和步数,否则遍历四个方向,将新节点压入栈中,同时标记为已经走过。这里只求了一条最短路径,如果要求所有的最短路径,可以使用广度优先搜索算法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值