DFS/BFS搜索迷宫路径

40 篇文章 7 订阅
38 篇文章 7 订阅

一、DFS搜索迷宫路径

DFS依赖栈结构

先把左上角节点入栈,然后依次查看栈顶元素的右、下、左、上四个方向是否可以走,如果能走就把节点入栈,然后再依次查看依次查看栈顶元素的右、下、左、上四个方向;如果四个方向都不能走,就把栈顶元素出栈

最终栈空,则说明退回到了左上角的节点;右下角的节点入栈,则表示找到了出口
在这里插入图片描述
需要注意的是,每入栈一个节点:

  • 需要将当前节点到入栈节点的方向置为NO,保证如果走进死胡同回退后,不会再次往这个错误的方向走
  • 需要将刚入栈节点到当前节点的方向置为NO,保证走过去后不会以入栈的方式走回来,想走回来只能以出栈的方式回退
#include <iostream>
#include <stack>
#include <memory>

using namespace std;

const int RIGHT = 0;
const int DOWN = 1;
const int LEFT = 2;
const int UP = 3;

const int D_NUM = 4;

const int YES = 0;
const int NO = 1;

class Maze {
public:
	Maze(int row, int col)
		: row_(row)
		, col_(col)
	{
		p_maze_ = new Node*[row_];
		for (int j = 0; j < col_; j++) {
			p_maze_[j] = new Node[col_];
		}
	}

	~Maze() {
		for (int i = 0; i < row_; i++) {
			delete[] p_maze_[i];
		}
	}

	void init_node(int i, int j, int val) {
		p_maze_[i][j].x_ = i;
		p_maze_[i][j].y_ = j;
		p_maze_[i][j].val_ = val;
		// 右下左上
		for (int idx = 0; idx < D_NUM; idx++) {
			p_maze_[i][j].direction_[idx] = NO;
		}
	}

	void set_node_state() {
		for (int i = 0; i < row_; i++) {
			for (int j = 0; j < col_; j++) {
				if (p_maze_[i][j].val_ == 1) {
					continue;
				}
				if (j < col_ - 1 && p_maze_[i][j + 1].val_ == 0) {
					p_maze_[i][j].direction_[RIGHT] = YES;
				}
				if (i < row_ - 1 && p_maze_[i + 1][j].val_ == 0) {
					p_maze_[i][j].direction_[DOWN] = YES;
				}
				if (j > 0 && p_maze_[i][j - 1].val_ == 0) {
					p_maze_[i][j].direction_[LEFT] = YES;
				}
				if (i > 0 && p_maze_[i - 1][j].val_ == 0) {
					p_maze_[i][j].direction_[UP] = YES;
				}
			}
		}
	}

	void search_maze_path() {
		if (p_maze_[0][0].val_ == 1) {
			return;
		}

		st_.push(p_maze_[0][0]);
		while (!st_.empty()) {
			Node top = st_.top();
			int x = top.x_;
			int y = top.y_;

			if (x == row_ - 1 && y == col_ - 1) {
				// 已将右下角的节点入栈
				return;
			}
			
			if (p_maze_[x][y].direction_[RIGHT] == YES) {
				p_maze_[x][y].direction_[RIGHT] = NO;
				p_maze_[x][y + 1].direction_[LEFT] = NO;
				st_.push(p_maze_[x][y + 1]);
				continue;
			}
			if (p_maze_[x][y].direction_[DOWN] == YES) {
				p_maze_[x][y].direction_[DOWN] = NO;
				p_maze_[x + 1][y].direction_[UP] = NO;
				st_.push(p_maze_[x + 1][y]);
				continue;
			}
			if (p_maze_[x][y].direction_[LEFT] == YES) {
				p_maze_[x][y].direction_[LEFT] = NO;
				p_maze_[x][y - 1].direction_[RIGHT] = NO;
				st_.push(p_maze_[x][y - 1]);
				continue;
			}
			if (p_maze_[x][y].direction_[UP] == YES) {
				p_maze_[x][y].direction_[UP] = NO;
				p_maze_[x - 1][y].direction_[DOWN] = NO;
				st_.push(p_maze_[x - 1][y]);
				continue;
			}
			// 当前节点四周都不能走,需要回溯,元素出栈
			st_.pop();
		}
	}

	void show_path() {
		if (st_.empty()) {
			cout << "找不到路径!" << endl;
			return;
		}

		while (!st_.empty()) {
			Node top = st_.top();
			p_maze_[top.x_][top.y_].val_ = '*';
			st_.pop();
		}
		for (int i = 0; i < row_; i++) {
			for (int j = 0; j < col_; j++) {
				if (p_maze_[i][j].val_ == '*') {
					cout << "* ";
				}
				else {
					cout << p_maze_[i][j].val_ << " ";
				}
			}
			cout << endl;
		}
	}

private:
	struct Node {
		Node()
			:x_(0)
			,y_(0)
			,val_(0)
		{
			for (int i = 0; i < D_NUM; ++i) {
				direction_[i] = NO;
			}
		}
		int x_;
		int y_;
		int val_;
		int direction_[D_NUM];
	};

	Node** p_maze_;
	int row_;
	int col_;
	stack<Node> st_;  // 用于深度搜索迷宫路径
};

int main() {
	cout << "请输入迷宫的行列:";
	int row;
	int col;
	int val;
	cin >> row >> col;
	Maze maze(row, col);

	cout << "请输入迷宫的结构:" << endl;
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			cin >> val;
			maze.init_node(i, j, val);
		}
	}

	maze.set_node_state();

	maze.search_maze_path();

	maze.show_path();
	return 0;
}

在这里插入图片描述
在这种情况下,虽然找到了迷宫的出口,但这不是最优路径

二、BFS搜索迷宫路径

BFS依赖队列结构

把[0,0]节点入队列,开启循环,分别查看对头节点的右、上、左、下四个方向是否能走,把能走的节点入队列。处理完队头节点后则队头元素出队

由于先入队的先处理,那肯定是先将当前队头节点周围可走的节点全部入队,然后依次处理,再处理更远处的节点,这就是广度优先遍历
在这里插入图片描述
我们边入队队头节点周围可走的节点,边出队队头节点,如果最终找到了迷宫出口的路径,那也没有记录这条路径,我们需要额外开辟一个数组记录搜索路径的过程

在这里插入图片描述
在这里插入图片描述
如果找到了出口,我们从[m,n]出发倒推迷宫的路径,直到碰到[0,0]停止

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

const int RIGHT = 0;
const int DOWN = 1;
const int LEFT = 2;
const int UP = 3;

const int D_NUM = 4;

const int YES = 0;
const int NO = 1;

class Maze {
public:
	Maze(int row, int col)
		: row_(row)
		, col_(col)
	{
		p_maze_ = new Node * [row_];
		for (int j = 0; j < col_; j++) {
			p_maze_[j] = new Node[col_];
		}
		path_.resize(row * col);
	}

	~Maze() {
		for (int i = 0; i < row_; i++) {
			delete[] p_maze_[i];
		}
	}

	void init_node(int i, int j, int val) {
		p_maze_[i][j].x_ = i;
		p_maze_[i][j].y_ = j;
		p_maze_[i][j].val_ = val;
		// 右下左上
		for (int idx = 0; idx < D_NUM; idx++) {
			p_maze_[i][j].direction_[idx] = NO;
		}
	}

	void set_node_state() {
		for (int i = 0; i < row_; i++) {
			for (int j = 0; j < col_; j++) {
				if (p_maze_[i][j].val_ == 1) {
					continue;
				}
				if (j < col_ - 1 && p_maze_[i][j + 1].val_ == 0) {
					p_maze_[i][j].direction_[RIGHT] = YES;
				}
				if (i < row_ - 1 && p_maze_[i + 1][j].val_ == 0) {
					p_maze_[i][j].direction_[DOWN] = YES;
				}
				if (j > 0 && p_maze_[i][j - 1].val_ == 0) {
					p_maze_[i][j].direction_[LEFT] = YES;
				}
				if (i > 0 && p_maze_[i - 1][j].val_ == 0) {
					p_maze_[i][j].direction_[UP] = YES;
				}
			}
		}
	}

	void search_maze_path() {
		if (p_maze_[0][0].val_ == 1) {
			return;
		}

		queue_.push(p_maze_[0][0]);
		while (!queue_.empty()) {
			Node front = queue_.front();
			int x = front.x_;
			int y = front.y_;

			// 查看四个方向是否能走,把能走的节点放入队列
			if (p_maze_[x][y].direction_[RIGHT] == YES) {
				p_maze_[x][y].direction_[RIGHT] = NO;
				p_maze_[x][y + 1].direction_[LEFT] = NO;
				
				queue_.push(p_maze_[x][y + 1]);
				path_[x*row_ + y+1] = p_maze_[x][y];         // 表示是从p_maze_[x][y]走到p_maze_[x][y + 1]的
				if (is_exit(x, y + 1)) {
					return;
				}
			}
			if (p_maze_[x][y].direction_[DOWN] == YES) {
				p_maze_[x][y].direction_[DOWN] = NO;
				p_maze_[x + 1][y].direction_[UP] = NO;
				queue_.push(p_maze_[x + 1][y]);
				path_[(x+1)*row_ + y] = p_maze_[x][y];
				if (is_exit(x + 1, y)) {
					return;
				}
			}
			if (p_maze_[x][y].direction_[LEFT] == YES) {
				p_maze_[x][y].direction_[LEFT] = NO;
				p_maze_[x][y - 1].direction_[RIGHT] = NO;
				queue_.push(p_maze_[x][y - 1]);
				path_[x * row_ + y - 1] = p_maze_[x][y];
				if (is_exit(x, y - 1)) {
					return;
				}
			}
			if (p_maze_[x][y].direction_[UP] == YES) {
				p_maze_[x][y].direction_[UP] = NO;
				p_maze_[x - 1][y].direction_[DOWN] = NO;
				queue_.push(p_maze_[x - 1][y]);
				path_[(x - 1) * row_ + y] = p_maze_[x][y];
				if (is_exit(x - 1, y)) {
					return;
				}
			}
			// 处理完队头节点,则出队列
			queue_.pop();
		}
	}

	void show_path() {
		if (queue_.empty()) {
			cout << "迷宫不存在路径!" << endl;
		}
		int x = row_ - 1;
		int y = col_ - 1;
		while (true) {
			p_maze_[x][y].val_ = '*';
			if (x == 0 && y == 0) {
				break;
			}
			Node node = path_[x * row_ + y];
			x = node.x_;
			y = node.y_;
		}

		for (int i = 0; i < row_; ++i) {
			for (int j = 0; j < col_; ++j) {
				if (p_maze_[i][j].val_ == '*') {
					cout << "* ";
				}
				else {
					cout << p_maze_[i][j].val_ << " ";
				}
			}
			cout << endl;
		}
	}

private:
	bool inline is_exit(int x, int y) {
		return x == row_ - 1 && y == col_ - 1;
	}

	struct Node {
		Node()
			:x_(0)
			,y_(0)
			,val_(0)
		{
			for (int i = 0; i < D_NUM; ++i) {
				direction_[i] = NO;
			}
		}
		int x_;
		int y_;
		int val_;
		int direction_[D_NUM];
	};

	Node** p_maze_;
	int row_;
	int col_;
	queue<Node> queue_;  // 用于广度搜索路径
	vector<Node> path_;  // 用于记录路径
};

int main() {
	cout << "请输入迷宫的行列:";
	int row;
	int col;
	int val;
	cin >> row >> col;
	Maze maze(row, col);

	cout << "请输入迷宫的结构:" << endl;
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			cin >> val;
			maze.init_node(i, j, val);
		}
	}

	maze.set_node_state();

	maze.search_maze_path();

	maze.show_path();
	return 0;
}

在这里插入图片描述

int main() {
	int m, n;
	cin >> m >> n;
	vector<vector<char>> grid(m, vector<char>(n));
	vector<vector<bool>> visited(m, vector<bool>(n));
	getchar();
	queue<pair<int, int>> q;
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			grid[i][j] = getchar();
			if (grid[i][j] == 's') {
				q.push({i, j});
				visited[i][j] = true;
			}
			else if (grid[i][j] == '#') {
				visited[i][j] = true;
			}
		}
		getchar();
	}
	
	int ans = 0;
	bool isReach = false;
	vector<vector<int>> directions = { {0,-1},{0,1},{1,0},{-1,0} };
	while (!q.empty()) {
		int cnt = q.size();
		for (int i = 0; i < cnt; i++) {
			pair<int, int> pos = q.front();
			q.pop();
			int x = pos.first;
			int y = pos.second;
			if (grid[x][y] == 'e') {
				isReach = true;
				break;
			}
			for (auto d : directions) {
				int x1 = x + d[0];
				int y1 = y + d[1];
				if (x1 < 0 || x1 >= m || y1 < 0 || y1 >= n) {
					continue;
				}
				if (!visited[x1][y1]) {
					q.push({x1, y1});
					visited[x1][y1] = true;  // 放进去就访问过了
				}
			}
		}
		if (isReach) {
			break;
		}
		ans++;
	}
	if (isReach) {
		cout << ans;
	}
	else {
		cout << -1;
	}
	
	
	return 0;
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

bugcoder-9905

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值