一、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;
}