[C/C++] -- 搜索迷宫路径

DFS(深度优先搜索)和BFS(广度优先搜索)是两种常用的图遍历算法,它们在搜索图或树中的节点时有着不同的策略和特点。

  1. 深度优先搜索 (DFS):

    • 在DFS中,从起始节点开始,沿着一条路径尽可能深地搜索,直到到达叶子节点或者无法继续搜索为止,然后回溯到上一个节点,选择另一条路径继续搜索,直到所有节点都被访问。
    • DFS通常使用递归或者来实现,递归是自然而直观的实现方式,而使用栈可以避免递归的潜在问题(如栈溢出)。
    • DFS的优点是在搜索过程中不需要记录所有访问过的节点,因此占用的空间较少。
    • 适用于寻找深度路径,比如解决迷宫问题、寻找图的连通分量等。
  2. 广度优先搜索 (BFS):

    • 在BFS中,从起始节点开始,首先访问起始节点的所有邻居节点,然后依次访问这些邻居节点的邻居节点,以此类推,直到所有节点都被访问。
    • BFS通常使用队列来实现,保证了节点的访问顺序是按照距离起始节点的距离逐层递增的。
    • BFS的优点是可以找到起始节点到目标节点的最短路径,而且在无权图中具有最优性(即找到的第一个解就是最短路径)。
    • 适用于寻找最短路径,比如在迷宫中找到最短路径、在社交网络中找到两个人之间的最短关系链等。

1.深度优先遍历DFS

设计一个程序,能够对给定的迷宫进行路径搜索,并输出一条从起点到终点的路径。具体来说,程序需要实现以下功能:

  1. 接受用户输入的迷宫地图,包括迷宫的行数和列数,以及每个格子的状态(0 表示可通行,1 表示不可通行)。
  2. 使用深度优先搜索算法(DFS)对迷宫进行搜索,找到从起点到终点的一条路径。
  3. 输出搜索到的路径。

入栈以后,然后我们查看栈顶元素,是(0,0)这个节点。栈现在不为空,取栈顶元素,先看它右边能不能走,能走的话,就一直向右走,它右边是0,就入栈了。

_pMaze[0][0]._val == 1
    return;
_stack. Push(_pMaze[0][0]);//左上角节点入栈 
while (!_stack. Empty())//栈不为空 
	Node top = _stack. Top();

 如果栈顶元素的右边可以走的话,我们要把当前节点的右方向改成不能走,把右边节点的左方向改成不能走。因为不能走回头路,而且因为路子走不通回退后也不能继续走相同的死路。

//往右方向寻找
			if (_pMaze[x][y]._state[RIGHT] == YES)
			{
				_pMaze[x][y]._state[RIGHT] = NO;
				_pMaze[x][y + 1]._state[LEFT] = NO;
				_stack.push(_pMaze[x][y + 1]);
				continue;

深度遍历入栈后,不用判断之前节点的方向。continue后,重新取栈顶元素,继续进行判断。同理,如果右边不能走,下边可以走的话:

//往下方向寻找
			if (_pMaze[x][y]._state[DOWN] == YES)
			{
				_pMaze[x][y]._state[DOWN] = NO;
				_pMaze[x + 1][y]._state[UP] = NO;
				_stack.push(_pMaze[x + 1][y]);
				continue;
			}

 同理:左方向

//往左方向寻找
			if (_pMaze[x][y]._state[LEFT] == YES)
			{
				_pMaze[x][y]._state[LEFT] = NO;
				_pMaze[x][y - 1]._state[RIGHT] = NO;
				_stack.push(_pMaze[x][y - 1]);
				continue;
			}

如果栈顶元素判断完四个方向都不能走,就是到死路了,就把栈顶元素出栈。
然后再取栈顶元素,进行判断,如果它的4个方向都不能走,就出栈,如果栈为空,则迷宫无通路。如果有方向能走,就继续走下去。以此类推下去。但是,都要判断一下此节点是不是右下角的节点,如果是,就是找到通路了。

//已经找到右下角出口得迷宫路径
			if (x == _row - 1 && y == _col - 1)
			{
				return;
			}

 完整代码:

#include <iostream>
#include <stack>
using namespace std;

//定义迷宫每一个节点的四个方向
const int RIGHT = 0;//右 
const int DOWN = 1;//下 
const int LEFT = 2;//左 
const int UP = 3;//上 

//迷宫每一个节点方向的数量
const int WAY_NUM = 4;

//定义节点行走状态
const int YES = 4;//当前方向可以走 
const int NO = 5;//当前方向不能走 

//迷宫
class Maze
{
public:
	//初始化迷宫,根据用户输入的行列数,生成存储迷宫路径信息的二维数组
	Maze(int row, int col)
		:_row(row)
		, _col(col)
	{
		_pMaze = new Node*[_row];//注意元素类型是Node 
		for (int i = 0; i < _row; ++i)
		{
			_pMaze[i] = new Node[_col];
		}
	}

	//初始化迷宫路径节点信息
	void initNode(int x, int y, int val)
	{
		_pMaze[x][y]._x = x;
		_pMaze[x][y]._y = y;
		_pMaze[x][y]._val = val;
		//节点四个方向默认的初始化都为不能走 
		for (int i = 0; i < WAY_NUM; ++i)
		{
			_pMaze[x][y]._state[i] = NO;
		}
	}

	//初始化迷宫0节点四个方向的行走状态信息 当前节点右下左上,如果是0,改成可以走 
	void setNodeState()
	{
		for (int i = 0; i < _row; ++i)
		{
			for (int j = 0; j < _col; ++j)
			{
				if (_pMaze[i][j]._val == 1)
				{
					continue;//不用调整了,因为走不到值为1的节点 
				}
				
                //j不能取到最后一列,不然就判断越界了 
				if (j < _col - 1 && _pMaze[i][j + 1]._val == 0)
				//逻辑&,是先计算左边的表达式,左边如果是false,右边就不用计算了 
				{
					_pMaze[i][j]._state[RIGHT] = YES;
				}

				if (i < _row - 1 && _pMaze[i + 1][j]._val == 0)
				{
					_pMaze[i][j]._state[DOWN] = YES;
				}
				
                //j不用取第一类,因为本身就不能走 
				if (j > 0 && _pMaze[i][j - 1]._val == 0)
				{
					_pMaze[i][j]._state[LEFT] = YES;
				}

				if (i > 0 && _pMaze[i - 1][j]._val == 0)
				{
					_pMaze[i][j]._state[UP] = YES;
				}
			}
		}
	}

	//深度搜索迷宫路径
	void searchMazePath()
	{
		if (_pMaze[0][0]._val == 1)
		{
			return;
		}
		_stack.push(_pMaze[0][0]);//左上角节点入栈 

		while (!_stack.empty())//栈不为空 
		{
			Node top = _stack.top();
			int x = top._x;
			int y = top._y;

			//已经找到右下角出口得迷宫路径
			if (x == _row - 1 && y == _col - 1)
			{
				return;
			}

			//往右方向寻找
			if (_pMaze[x][y]._state[RIGHT] == YES)
			{
				_pMaze[x][y]._state[RIGHT] = NO;
				_pMaze[x][y + 1]._state[LEFT] = NO;
				_stack.push(_pMaze[x][y + 1]);
				continue;
			}

			//往下方向寻找
			if (_pMaze[x][y]._state[DOWN] == YES)
			{
				_pMaze[x][y]._state[DOWN] = NO;
				_pMaze[x + 1][y]._state[UP] = NO;
				_stack.push(_pMaze[x + 1][y]);
				continue;
			}

			//往左方向寻找
			if (_pMaze[x][y]._state[LEFT] == YES)
			{
				_pMaze[x][y]._state[LEFT] = NO;
				_pMaze[x][y - 1]._state[RIGHT] = NO;
				_stack.push(_pMaze[x][y - 1]);
				continue;
			}

			//往上方向寻找
			if (_pMaze[x][y]._state[UP] == YES)
			{
				_pMaze[x][y]._state[UP] = NO;
				_pMaze[x - 1][y]._state[DOWN] = NO;
				_stack.push(_pMaze[x - 1][y]);
				continue;
			}

			_stack.pop();
		}
	}

	//打印迷宫路径搜索结果
	void showMazePath()
	{
		if (_stack.empty())
		{
			cout << "不存在一条迷宫路径!" << endl;
		}
		else
		{
			while (!_stack.empty())//栈不为空,取出节点坐标,相应值调整为* 
			{
				Node top = _stack.top();
				_pMaze[top._x][top._y]._val = '*';
				_stack.pop();
			}

			for (int i = 0; i < _row; ++i)//打印迷宫
			{
				for (int j = 0; j < _col; ++j)
				{
					if (_pMaze[i][j]._val == '*')
					{
						cout << "* ";
					}
					else
					{
						cout << _pMaze[i][j]._val << " ";
					}
				}
				cout << endl;
			}
		}
	}
private:
	//定义迷宫节点路径信息
	struct Node
	{
		int _x;//节点的横坐标 
		int _y;//节点的纵坐标 
		int _val;//节点的值
		int _state[WAY_NUM];//记录节点四个方向的状态(左右上下)
		//4个元素位置(左右上下),存储yes或者no 
	};

	Node **_pMaze;//动态生成迷宫路径(动态开辟二维数组) 
	int _row;//迷宫的行 
	int _col;//迷宫的列 
	stack<Node> _stack;//栈结构,辅助深度搜索迷宫路径
};

int main()
{
	cout << "请输入迷宫的行列数(例如:10 10):";
	int row, col, data;
	cin >> row >> col;

	Maze maze(row, col);//创建迷宫对象

	cout << "请输入迷宫的路径信息(0表示可以走,1表示不能走):" << endl;
	for (int i = 0; i < row; ++i)//只能获取i,j和data值,节点的4个方向的行走状态还不能初始化 
	{
		for (int j = 0; j < col; ++j)
		{
			cin >> data;
			//可以初始化迷宫节点的基本信息
			maze.initNode(i, j, data);
		}
	}

	//开始设置所有节点的四个方向的状态
	maze.setNodeState();

	//开始从左上角搜索迷宫的路径信息了
	maze.searchMazePath();

	//打印迷宫路径搜索的结果
	maze.showMazePath();

	return 0;
}

 

 2.广度优先遍历BFS

#include <iostream>
#include <queue>
#include <vector>
using namespace std;

//定义方向
const int RIGHT = 0;
const int DOWN = 1;
const int LEFT = 2;
const int UP = 3;
const int WAY_NUM = 4;

//定义行走状态
const int YES = 4;
const int NO = 5;

//迷宫
class Maze
{
public:
	Maze(int row, int col)
		:_row(row)
		, _col(col)
	{
		_pMaze = new Node*[_row];//开辟迷宫二维数组 
		for (int i = 0; i < _row; ++i)
		{
			_pMaze[i] = new Node[_col];
		}

		//node._x*_row + node._y
		_pPath.resize(_row * _col);//辅助数组开辟空间 
	}

	void initNode(int x, int y, int val)//初始化为No 
	{
		_pMaze[x][y]._x = x;
		_pMaze[x][y]._y = y;
		_pMaze[x][y]._val = val;
		for (int i = 0; i < WAY_NUM; ++i)
		{
			_pMaze[x][y]._state[i] = NO;
		}
	}

	void setNodeState()//设置迷宫行走状态 
	{
		for (int i = 0; i < _row; ++i)
		{
			for (int j = 0; j < _col; ++j)
			{
				if (_pMaze[i][j]._val == 1)
				{
					continue;
				}

				if (j < _col - 1 && _pMaze[i][j + 1]._val == 0)
				{
					_pMaze[i][j]._state[RIGHT] = YES;
				}

				if (i < _row - 1 && _pMaze[i + 1][j]._val == 0)
				{
					_pMaze[i][j]._state[DOWN] = YES;
				}

				if (j > 0 && _pMaze[i][j - 1]._val == 0)
				{
					_pMaze[i][j]._state[LEFT] = YES;
				}

				if (i > 0 && _pMaze[i - 1][j]._val == 0)
				{
					_pMaze[i][j]._state[UP] = YES;
				}
			}
		}
	}

	void searchMazePath()//广度优先遍历搜索 
	{
		if (_pMaze[0][0]._val == 1)
		{
			return;
		}
		_queue.push(_pMaze[0][0]);//入口节点入队 

		while (!_queue.empty())//队列不为空 
		{
			Node front = _queue.front();//获取队头元素 
			int x = front._x;
			int y = front._y;

			//右方向
			if (_pMaze[x][y]._state[RIGHT] == YES)
			{
				_pMaze[x][y]._state[RIGHT] = NO;
				_pMaze[x][y + 1]._state[LEFT] = NO;
				//在辅助数组中记录一下节点的行走信息
				_pPath[x*_row + y + 1] = _pMaze[x][y];
				_queue.push(_pMaze[x][y + 1]);
				if (check(_pMaze[x][y + 1]))
					return;
			}

			//下方向
			if (_pMaze[x][y]._state[DOWN] == YES)
			{
				_pMaze[x][y]._state[DOWN] = NO;
				_pMaze[x + 1][y]._state[UP] = NO;
				_pPath[(x + 1)*_row + y] = _pMaze[x][y];
				_queue.push(_pMaze[x + 1][y]);
				if (check(_pMaze[x + 1][y]))
					return;
			}

			//左方向
			if (_pMaze[x][y]._state[LEFT] == YES)
			{
				_pMaze[x][y]._state[LEFT] = NO;
				_pMaze[x][y - 1]._state[RIGHT] = NO;
				_pPath[x*_row + y - 1] = _pMaze[x][y];
				_queue.push(_pMaze[x][y - 1]);
				if (check(_pMaze[x][y - 1]))
					return;
			}

			//上方向
			if (_pMaze[x][y]._state[UP] == YES)
			{
				_pMaze[x][y]._state[UP] = NO;
				_pMaze[x - 1][y]._state[DOWN] = NO;
				_pPath[(x - 1)*_row + y] = _pMaze[x][y];
				_queue.push(_pMaze[x - 1][y]);
				if (check(_pMaze[x - 1][y]))
					return;
			}

			//当前节点出队列
			_queue.pop();
		}
	}

	void showMazePath()//打印迷宫 
	{
		if (_queue.empty())
		{
			cout << "不存在一条迷宫路径!" << endl;
		}
		else
		{
			//回溯寻找迷宫路径节点
			int x = _row - 1;
			int y = _col - 1;
			for (;;)
			{
				_pMaze[x][y]._val = '*';
				if (x == 0 && y == 0)
					break;
				Node node = _pPath[x*_row + y];
				x = node._x;
				y = node._y;
			}

			for (int i = 0; i < _row; ++i)
			{
				for (int j = 0; j < _col; ++j)
				{
					if (_pMaze[i][j]._val == '*')
					{
						cout << "* ";
					}
					else
					{
						cout << _pMaze[i][j]._val << " ";
					}
				}
				cout << endl;
			}
		}
	}
private:
	//定义迷宫节点路径信息
	struct Node
	{
		int _x;
		int _y;
		int _val;//节点的值
		int _state[WAY_NUM];//记录节点四个方向的状态
	};

	//检查是否是右下角的迷宫出口节点
	bool check(Node &node)
	{
		return node._x == _row - 1 && node._y == _col - 1;
	}

	Node **_pMaze;//动态开辟二维数组 
	int _row;//行 
	int _col;//列 
	queue<Node> _queue;//广度遍历依赖的队列结构
	vector<Node> _pPath;//记录广度优先遍历时,节点的行走信息,辅助数组 
};

int main()
{
	cout << "请输入迷宫的行列数(例如:10 10):";
	int row, col, data;
	cin >> row >> col;

	Maze maze(row, col);//创建迷宫对象

	cout << "请输入迷宫的路径信息(0表示可以走,1表示不能走):" << endl;
	for (int i = 0; i < row; ++i)
	{
		for (int j = 0; j < col; ++j)
		{
			cin >> data;
			//可以初始化迷宫节点的基本信息
			maze.initNode(i, j, data);
		}
	}

	//开始设置所有节点的四个方向的状态
	maze.setNodeState();

	//开始从左上角搜索迷宫的路径信息了
	maze.searchMazePath();

	//打印迷宫路径搜索的结果
	maze.showMazePath();

	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/619363.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于数据挖掘与机器学习揭秘脱发主因

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 基于数据挖掘与机器学习揭秘脱发主因 目录 一、绪论背景描述数据说明内容大概 二、导入包以及数据读取三、数据预览四、探究导致脱发的因素4.1…

萤火虫优化算法(Firefly Algorithm)

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 算法背景 萤火虫优化算法&#xff0c;是由剑桥大学的Xin-She Yang在2009年提出的一种基于群体智能的优化算法。它的灵感来源于萤火虫在夜晚闪烁…

[AIGC] 跳跃表是如何实现的?原理?

文章目录 什么是跳跃表查找流程&#xff1a;为什么使用跳跃表?跳跃表是怎么实现的&#xff1f; PS:跳跃表是比较常问的一种结构。 什么是跳跃表 Skip Lists: A Probabilistic Alternative to Balanced Trees 跳跃表是一种可以用来代替平衡树的数据结构。跳跃表使用概率平衡…

微服务核心01-Maven【项目管理工具】高级

一、分模块开发与设计&#xff08;重点⭐&#xff09; ssm_pojo 拆分 新建模块拷贝原始项目中对应的相关内容到 ssm_pojo 模块中 实体类 &#xff08;User&#xff09;配置 文件&#xff08;无&#xff09; ssm_dao 拆分 ssm_service 拆分 ssm_control 拆分 二、聚合&#xff…

齿轮滚刀刃口钝化技术简介

介绍 在滚刀的使用中发现&#xff0c;进口滚刀和国产滚刀在加工质量和寿命方面存在显著差异。经过多次比较得知&#xff0c;滚刀的使用寿命可以达到国产滚刀的两倍以上&#xff0c;而进口滚刀返回原厂磨削后的使用寿命约为新刀具的90% &#xff0c;但同样经过国内厂家磨削后&a…

第 1 天_二分查找【算法基础】

第 1 天_二分查找 前言34. 在排序数组中查找元素的第一个和最后一个位置题解官方33. 搜索旋转排序数组题解官方74. 搜索二维矩阵 前言 这是陈旧已久的草稿2021-11-09 19:33:44 当时在学习数据结构&#xff0c;然后再LeetCode上找了一个算法基础。 但是后来又没做了。 现在20…

1. 抓娃娃-二分

因为这个限制&#xff0c;所以不用担心线段比区间长 线段一定比区间短的话&#xff0c;想要判断是否线段的二分之一及以上在区间内&#xff0c;则可以转化为线段中点是否在区间内的问题 如果没有那个限制&#xff0c;那么就无法这么考虑了&#xff0c;因为即使中点在区间内&…

PUBG非升级实用枪皮-部分盘点

藏匿处的黑货箱武器需要耗费高额成本才能升级 对于像我这样的日常休闲玩家来说是一笔不小的&#xff08;巨大的&#xff01;&#xff09;负担 其实有许多普通非升级枪皮也是不错的选择 今天就来盘点一下我自己日常在用的普通皮 来看看你是不是也在用一样的 &#xff08;仅是盘点…

251 基于matlab的动态粒子群算法

基于matlab的动态粒子群算法。普通粒子群算法无法感知外界环境的变化&#xff0c;在外界环境发生改变时无法实时进行响应&#xff0c;因而缺乏动态环境寻优能力。在普通粒子群算法基本上通过增加敏感粒子得到一种动态粒子群算法&#xff0c;该算法通过实时计算敏感粒子的适应度…

系统权限控制插件封装-实现系统权限控制插件化

背景&#xff1a;按照传统的开发方式方式&#xff0c;每次新开发一个系统&#xff0c;就需要花费大量时间精力去搭建权限控制模块&#xff0c;如果我们把权限控制这一整个模块都抽离成一个独立的权限控制插件&#xff0c;支持单命令安装&#xff0c;全面暴露参数与方法&#xf…

【算法】竞赛常用知识之字符串1

前言&#xff1a; 本系列是学习了董晓老师所讲的知识点做的笔记 董晓算法的个人空间-董晓算法个人主页-哔哩哔哩视频 (bilibili.com) 动态规划系列&#xff08;还没学完&#xff09; 【算法】动态规划之线性DP问题-CSDN博客 【算法】动态规划之背包DP问题&#xff08;2024…

Linux中云盘/磁盘,爆满处理方式

1&#xff1a;du和df命令查看磁盘大小不一致 以下是阿里云服务器云盘使用率 运行 du -sh / 大小为20g 我的服务器大小为40g 按道理说这个云盘使用率应该是百分之五十 而运行 df -h / 这个命令是跟这个云盘使用率差不多的。 1.1分析原因 我安装了mysql&#xff0c;nginx…

47岁古天乐唯一承认女友约「御用阿妈」过母亲节

日前关宝慧在IG晒出一张聚会照&#xff0c;并写道&#xff1a;「预祝各位#母亲节快乐&#x1f339;#dinner #happy #friends #好味」相中所见&#xff0c;前TVB金牌监制潘嘉德、卢宛茵、黄&#x28948;莹、黎萨达姆都有出席饭局。 当中黄&#x28948;莹身穿卡其色西装褛&…

从“制造”到“智造”:“灯塔”经验助力中国制造业转型升级-转载

作者&#xff1a;Karel Eloot&#xff0c;侯文皓&#xff0c;Francisco Betti&#xff0c;Enno de Boer和Yves Giraud 作为中国实体经济的主体&#xff0c;制造业是推动中国经济发展乃至全球制造业持续增长的重要引擎。站在历史与未来交汇的新起点上&#xff0c;中国制造业将背…

ERP与MES与WMS集成

WMS储位管理 WMS与MES集成 (一) 打通追溯链 在拣货时&#xff0c;将配料标签与供应商的物料标签进行关联。通过配料标签达到精确追溯及防错目的。针对模糊查询&#xff0c;将工单与物料的供应商信息、仓库流转信息进行关联。 (二) WMS入库 成品(半成品)下线后&#xff0c;M…

MySQL查询篇-聚合函数-窗口函数

文章目录 distinct 关键字聚合函数常见的聚合函数group by和having 分组过滤 窗口函数with as窗口聚合函数排名窗口函数值窗口函数 distinct 关键字 distinct 去重数据&#xff0c;ps:null值也会查出来 select distinct column from table;聚合函数 常见的聚合函数 select …

【前端系列】什么是yarn

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

浅谈@Controller注解和其他四大注解的区别

各位大佬光临寒舍&#xff0c;希望各位能赏脸给个三连&#xff0c;谢谢各位大佬了&#xff01;&#xff01;&#xff01; 目录 1.Spring五大注解的使用约定 2.Controller注解的特别之处 3.总结 1.Spring五大注解的使用约定 Spring的五大注解&#xff08;Controller&#x…

【无标题】能效?性能?一个关于openssl speed速度测试的诡异问题。

问题描述 最近的某个软件用到了openssl&#xff0c;所以就想着测试一下速度。我的电脑是惠普的&#xff0c;CPU是AMD Ryzen 7 PRO 6850HS&#xff0c;系统是Win11。我使用openssl自带的speed测试加密/解密的速度&#xff0c;命令大致如下&#xff1a; openssl speed -evp aes…

python数据分析——matplotlib可视化基础

参考资料&#xff1a;活用pandas库 # 导入库 import pandas as pd import matplotlib.pyplot as plt # 导入数据 anscombepd.read_csv(r"...\seaborn常用数据案例\anscombe.csv") anscombe.head() 大多数基本图表的名字以plt.plot开头。 # 创建数据子集 # 只包含数…