迷宫寻路之BFS最短路径算法
写博客记录一下,还望大神指点。
- BFS又叫广度优先搜索算法,就是利用队列这个数据结构与while循环,以发散搜索的方式一层一层的去遍历整个图。这个一层一层比较重要,因为刚好是这个东西能让我们找到迷宫的最短路径。
- BFS的基本思路就是:
- 初始化队列,将起始节点放入队尾
- While(队列不为空)
–取出队头节点Node
–弹出队头节点Node
–判断当前节点是否为终点
-----处理该节点Node
–把当前节点的相邻节点加入队尾
那么我们是怎么找到最短路径的呢?
- 先利用这个伪代码求一下下面这个迷宫的最短路径长度:
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 0 1 1 1 0 1
1 0 0 0 1 0 1
1 0 1 0 1 0 1
1 1 0 0 0 0 1
1 1 1 1 1 1 1
其中第二行加粗的是起点,第六行的是终点。
1.访问(1,1)这个点,这是第一层,不是终点,把相邻节点入队。
2.访问(2,1)这个点,这是第二层,不是终点,把相邻节点入队。
3.访问(1,2)这个点,这是第二层,不是终点,把相邻节点入队。
3.访问(3,1)这个点,这是第三层,不是终点,把相邻节点入队。
…
.访问(5,2)这个点,这是第八层,是终点,退出循环。
从这个过程中我们可以发现每次都会把相邻节点放到队尾,那么我们访问的时候就会先把同一层的访问完了,再访问下一层。而且,每一层与起点的距离就是层数减一,那么当找到终点时只需要输出这个层数减一,就得到了我们的最短路径长度。
现在要求的是最短路径(字符串)怎么办?
从上面的过程中我们发现,层数可以当成距离,那么可不可以给访问的的每一个节点再增加一个string类型的字符串,用来存储从起点到当前点的路径来解决这个问题呢。完全可以,只需要在每次入队的时候把当前这一步是怎么走的加入到这个字符串里,最后找到终点时,直接输出这个字符串就是要求的迷宫最短路径。
以下是我的代码:
#include <iostream>
#include <vector>
#include <queue>
#include <string>
#define STARTX 1//起点
#define STARTY 1
#define OVERX 5//终点
#define OVERY 2
using namespace std;
int maze[7][7] = { 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 1,
1, 0, 1, 1, 1, 0, 1,
1, 0, 0, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1,
1, 1, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1 };
struct Point {
int x, y;
string path;//存储路径
};
char dir[4] = { 'U','L','D','R' };
queue<Point> mazeQueue;
void BFSFindRoad();
int main() {
BFSFindRoad();
system("pause");
return 0;
}
/**
*节点入队并标记
*/
void pushPoint2Queue(int x, int y, string path) {
Point temp;
temp.x = x; temp.y = y; temp.path = path;
mazeQueue.push(temp);
maze[x][y] = 1;
}
void BFSFindRoad() {
Point temp;
//初始化队列
pushPoint2Queue(STARTX, STARTY,"");
while (!mazeQueue.empty()) {
temp = mazeQueue.front();
mazeQueue.pop();
if (temp.x == OVERX&&temp.y == OVERY) {
cout << "最短路径:"<< temp.path << endl;
return;
}
//邻接节点入队并添加路径
if (maze[temp.x - 1][temp.y] == 0) pushPoint2Queue(temp.x - 1, temp.y, temp.path + dir[0]);
if (maze[temp.x][temp.y - 1] == 0) pushPoint2Queue(temp.x, temp.y - 1, temp.path + dir[1]);
if (maze[temp.x + 1][temp.y] == 0) pushPoint2Queue(temp.x + 1, temp.y, temp.path + dir[2]);
if (maze[temp.x][temp.y + 1] == 0) pushPoint2Queue(temp.x, temp.y + 1, temp.path + dir[3]);
}
cout << "没发现路径" << endl;
}
我就是在存储路径的时候做了改进,不使用另外的一个数组来保存每一个点的前驱节点,直接使用路径变量保存路径。同时只有队列里的元素才会保存路径,避免了回溯输出路径的问题。书上那个也不叫回溯,只不过我觉得比较像回溯,因为它里面每个变量存了上一个节点的坐标,然后又通过这个坐标去找上上个坐标,还是比较像回溯。