迷宫我们都玩过,有些复杂的看的眼花缭乱,但是有没有想过,让机器帮你完成这个工作,想着就很酷,好,废话不多说
,直接开干!!!
解决迷宫问题可以有多种算法,这里介绍深度优先搜索跟广度优先算法。
深度优先搜索(DFS)和广度优先搜索(BFS)是两种常用的图遍历算法,适用于不同的问题和场景。下面我将对它们进行解释,并介绍它们的适用场景以及优缺点。
深度优先搜索(DFS):
适用场景:
优点:
缺点:
广度优先搜索(BFS):
适用场景:
优点:
缺点:
总结:
在实际应用中,根据问题的特点和需求,选择合适的算法来进行图遍历是非常重要的。
既然两种方法都能实现,那我就两个都实现了把,广度优先算法能找到最短路径,深度优先算法能尽快找出出口,各有优点。
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
struct Point {
int x;
int y;
Point(int x, int y) : x(x), y(y) {}
};
// 检查点是否在迷宫范围内
bool isValidPoint(const std::vector<std::vector<int>>& maze, int x, int y) {
int rows = maze.size();
int cols = maze[0].size();
return (x >= 0 && x < rows && y >= 0 && y < cols && maze[x][y] == 0);
}
// 解决迷宫问题-深度优先
bool solveMaze(std::vector<std::vector<int>>& maze, const Point& start, const Point& end) {
int rows = maze.size();
int cols = maze[0].size();
// 创建堆栈
std::stack<Point> stack;
stack.push(start);
// 创建标记矩阵,用于记录已访问的点
std::vector<std::vector<bool>> visited(rows, std::vector<bool>(cols, false));
visited[start.x][start.y] = true;
// 定义四个方向上的移动
int dx[] = { 0, 1, 0, -1 };
int dy[] = { -1, 0, 1, 0 };
while (!stack.empty()) {
Point current = stack.top();
// 如果当前点是终点,找到解决方案,返回真
if (current.x == end.x && current.y == end.y) {
// 标记路径上的位置为-1
while (!stack.empty()) {
Point point = stack.top();
maze[point.x][point.y] = -1;
stack.pop();
}
return true;
}
// 尝试四个方向上的移动
bool moved = false;
for (int i = 0; i < 4; i++) {
int newX = current.x + dx[i];
int newY = current.y + dy[i];
if (isValidPoint(maze, newX, newY) && !visited[newX][newY]) {
stack.push(Point(newX, newY));
visited[newX][newY] = true;
moved = true;
break;
}
}
// 如果无法移动到相邻点,则回溯到上一个点
if (!moved) {
stack.pop();
}
}
// 没有找到解决方案,返回假
return false;
}
// 打印迷宫图
void printMaze(const std::vector<std::vector<int>>& maze, const Point& start, const Point& end) {
int rows = maze.size();
int cols = maze[0].size();
// 输出上边框
for (int i = 0; i < cols + 2; i++) {
std::cout << "# ";
}
std::cout << std::endl;
// 输出迷宫内容
for (int i = 0; i < rows; i++) {
std::cout << "# "; // 左边框
for (int j = 0; j < cols; j++) {
if (i == start.x && j == start.y) {
std::cout << "S "; // 起点标记为"S"
}
else if (i == end.x && j == end.y) {
std::cout << "E "; // 终点标记为"E"
}
else if (maze[i][j] == 0) {
std::cout << " "; // 空路径
}
// 在路径上画线
else if (maze[i][j] == -1) {
std::cout << "x ";
}
else {
std::cout << "█ "; // 墙壁
}
}
std::cout << "#" << std::endl; // 右边框
}
// 输出下边框
for (int i = 0; i < cols + 2; i++) {
std::cout << "# ";
}
std::cout << std::endl;
}
int main() {
std::vector<std::vector<int>> maze = {
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1 },
{ 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1 },
{ 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1 },
{ 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1 },
{ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1 },
{ 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1 },
{ 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
{ 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
{ 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
{ 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
{ 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
};
Point start(1, 1);
Point end(13, 13);
std::cout << "初始迷宫:" << std::endl;
printMaze(maze, start, end);
bool isSolvable = solveMaze(maze, start, end);
if (isSolvable) {
std::cout << "迷宫可以解决!" << std::endl;
}
else {
std::cout << "迷宫无解!" << std::endl;
}
std::cout << "解决后的迷宫:" << std::endl;
printMaze(maze, start, end);
while(1);
return 0;
}
S代表起始点,E代表终点,x代表路径
这里使用了栈,stack是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口
栈中只有顶端的元素才可以被外界使用,因此栈不允许有遍历行为
栈中进入数据称为 — 入栈 push
栈中弹出数据称为 — 出栈 pop
生活中的栈:
深度优先搜索(DFS
):
#include <iostream>
#include <queue>
#include <vector>
struct Point {
int x;
int y;
Point(int x, int y) : x(x), y(y) {}
};
// 检查点是否在迷宫范围内
bool isValidPoint(const std::vector<std::vector<int>>& maze, int x, int y) {
int rows = maze.size();
int cols = maze[0].size();
return (x >= 0 && x < rows && y >= 0 && y < cols && maze[x][y] == 0);
}
// 解决迷宫问题并返回最短路径
std::vector<Point> solveMaze(std::vector<std::vector<int>>& maze, const Point& start, const Point& end) {
int rows = maze.size();
int cols = maze[0].size();
// 创建队列
std::queue<std::vector<Point>> queue;
queue.push({ start });
// 创建标记矩阵,用于记录已访问的点
std::vector<std::vector<bool>> visited(rows, std::vector<bool>(cols, false));
visited[start.x][start.y] = true;
// 定义四个方向上的移动
int dx[] = { 0, 1, 0, -1 };
int dy[] = { -1, 0, 1, 0 };
while (!queue.empty()) {
std::vector<Point> path = queue.front();
queue.pop();
Point current = path.back();
// 如果当前点是终点,找到解决方案,返回最短路径
if (current.x == end.x && current.y == end.y) {
return path;
}
// 尝试四个方向上的移动
for (int i = 0; i < 4; i++) {
int newX = current.x + dx[i];
int newY = current.y + dy[i];
if (isValidPoint(maze, newX, newY) && !visited[newX][newY]) {
std::vector<Point> newPath = path;
newPath.push_back(Point(newX, newY));
queue.push(newPath);
visited[newX][newY] = true;
}
}
}
// 没有找到解决方案,返回空路径表示无解
return {};
}
// 打印迷宫图
void printMaze(const std::vector<std::vector<int>>& maze, const Point& start, const Point& end) {
int rows = maze.size();
int cols = maze[0].size();
// 输出上边框
for (int i = 0; i < cols + 2; i++) {
std::cout << "# ";
}
std::cout << std::endl;
// 输出迷宫内容
for (int i = 0; i < rows; i++) {
std::cout << "# "; // 左边框
for (int j = 0; j < cols; j++) {
if (i == start.x && j == start.y) {
std::cout << "S "; // 起点标记为"S"
}
else if (i == end.x && j == end.y) {
std::cout << "E "; // 终点标记为"E"
}
else if (maze[i][j] == 0) {
std::cout << " "; // 空路径
}
else if (maze[i][j] == -1) {
std::cout << "x "; // 解决路径上的位置用"x"表示
}
else {
std::cout << "█ "; // 墙壁
}
}
std::cout << "#" << std::endl; // 右边框
}
// 输出下边框
for (int i = 0; i < cols + 2; i++) {
std::cout << "# ";
}
std::cout << std::endl;
}
int main() {
std::vector<std::vector<int>> maze = {
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1 },
{ 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1 },
{ 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1 },
{ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1 },
{ 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1 },
{ 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
{ 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
{ 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
{ 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1 },
{ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
};
Point start(1, 1);
Point end(13, 13);
std::cout << "初始迷宫:" << std::endl;
printMaze(maze, start, end);
std::vector<Point> shortestPath = solveMaze(maze, start, end);
if (!shortestPath.empty()) {
std::cout << "迷宫可以解决!最短路径长度为:" << shortestPath.size() - 1 << std::endl;
// 标记解决路径上的位置
for (const auto& point : shortestPath) {
maze[point.x][point.y] = -1;
}
}
else {
std::cout << "迷宫无解!" << std::endl;
}
std::cout << "解决后的迷宫:" << std::endl;
printMaze(maze, start, end);
while (1);
return 0;
}
广度优先使用的是Queue队列,队列是一种先进先出(First In First Out,FIFO)的数据结构,它有两个出口
队列容器允许从一端新增元素,从另一端移除元素
队列中只有队头和队尾才可以被外界使用,因此队列不允许有遍历行为
队列中进数据称为 — 入队 push
队列中出数据称为 — 出队 pop
生活中的队列:
广度优先搜索(BFS):