迷宫问题-DFS-BFS

news2024/11/24 13:46:50

迷宫问题

  • 迷宫问题简介
  • BFS解决迷宫最短路径问题
  • DFS记录迷宫路径
  • DFS解决迷宫所有路径问题

迷宫问题简介

🚀学习过算法程序设计的应该都学习过迷宫这个问题,迷宫问题主要设计的算法就是DFS-深度优先遍历和BFS-广度优先遍历。
🚀在一个二维数组中,元素为1的位置表示这个位置是墙,0表示有通路,迷宫的入口和出口都是0(否则不会有路径能出去),并且路径不唯一。例如下图:

在这里插入图片描述

🚀图中这个迷宫有两条路径,分别用粉色和蓝色标记了出来,明显粉色路径的长度是比蓝色路径要短的。

BFS解决迷宫最短路径问题

🚀BFS可以解决最短路径的原因是,BFS是像水波一样逐渐向外圈波及的,很明显最先波及到的通路就是最短路径。

🚀使用BFS算法的思想

一般的广度优先遍历都是采用队列完成的,每次取对头然后将其周围四个位置压到队列当中,然后pop掉对头,这样循环下去直到队列为空就停止。但是这种算法无法记录迷宫走过的路径,所以我才用vector来模拟队列来使用,就相当于对头的数据不pop掉,而是用一个下标来控制,现在走到哪个下标了,并且存储当前位置的结构体中多设置了一个变量prev,存储的是这个位置的上个位置在vector中的下标。这样在迷宫中走到终点的时候,返回这个vector,里面就有我们过的路径了。

🚀代码实现

struct path
{
	int _x;
	int _y;
	int _prev; // 在模拟对列中的下标位置
	path(int x,int y,int prev)
		:_x(x)
		,_y(y)
		,_prev(prev)
	{}
};
bool check(int i, int j, int map[][8], int row, int col)
{
	if (i < 0 || j < 0 || i > row - 1 || j > col - 1)
		return false;
	if (map[i][j] == -1) //走过的位置被设置为-1
		return false;
	if (map[i][j] == 1)
		return false;
	return true;
}

vector<path> BFS(int map[][8], int row, int col)
{
	vector<path> v;
	v.push_back(path(0, 0, -1));
	size_t index = 0;
	int fx[4] = { 0,1,-1,0 };
	int fy[4] = { 1,0,0,-1 };
	int i = 0, j = 0;//当前位置的横纵坐标
	while (index < v.size())
	{
		i = v[index]._x;
		j = v[index]._y;
		for (int k = 0; k < 4; k++)
		{
			int new_i = i + fx[k];
			int new_j = j + fy[k];
			if (check(new_i, new_j, map, 7, 8))
			{
				v.push_back(path(new_i, new_j, index));
				map[new_i][new_j] = -1;
				if (new_i == row - 1 && new_j == col - 1)
					return v;
			}
		}
		index++;
	}
	cout << "error" << endl;
	return v;
}
int main()
{
	int map[7][8] = {
		{0,0,0,1,1,1,1,1},
		{0,1,0,1,1,1,1,1},
		{0,1,0,1,0,0,0,1},
		{0,1,0,1,0,1,0,1},
		{0,1,0,0,0,1,0,1},
		{0,1,1,1,1,1,0,1},
		{0,0,0,0,0,0,0,0}
	};
	vector<path> res = BFS(map, 7, 8);
	int i = res.size() - 1;
	while (i >= 0)
	{
		cout << "(" << res[i]._x << "," << res[i]._y << ")" << endl;
		i = res[i]._prev;
	}
}

🚀运行结果
在这里插入图片描述
🚀你会发现打印的结果是从终点走向起点的,我们可以对其做一下修改。使用递归的方式逆向打印出结果。

void Print(vector<path>& v, int index)
{
	if (index == 0)
	{
		cout << "(" << v[index]._x << "," << v[index]._y << ")" << endl;
		return;
	}
	Print(v, v[index]._prev);
	cout << "(" << v[index]._x << "," << v[index]._y << ")" << endl;
}

🚀这样我们就能得到正向的路径了。
在这里插入图片描述

DFS记录迷宫路径

🚀BFS算法思想

深度优先搜索是,一条道走到黑,走不通再换另一条路,对于深度优先搜索,我们可以用栈来记录它的路径,每次进入程序后,先将当前位置压栈,再让他向上下左右去试探,值得注意的是要在最后进行弹栈处理,因为如果上下左右都我没有返回true表明从此位置出发是到不了终点的,说明此位置不在最终的路径当中,所以要弹栈。并且在开始的时候将此位置压栈后,要将此位置对应的数据改为-1,表明在后面的递归中不能往回走了(会造成死循环),并且在弹栈后要将此位置的值修改为0,这是因为这层函数栈帧已经结束,返回到上一层栈帧中,而返回到上一层栈帧的时候,这个位置是没有被访问的。

🚀代码实现

bool DFS(int map[][8], int row, int col, stack<_path>& st,int i,int j)
{
	st.push(_path(i, j));
	map[i][j] = -1;
	if (i == row - 1 && j == col - 1)
		return true;
	if (check(i + 1, j, map, 7, 8))
		if (DFS(map, 7, 8, st, i + 1, j))
			return true;
	if (check(i - 1, j, map, 7, 8))
		if (DFS(map, 7, 8, st, i - 1, j))
			return true;
	if (check(i, j + 1, map, 7, 8))
		if (DFS(map, 7, 8, st, i, j + 1))
			return true;
	if (check(i, j - 1, map, 7, 8))
		if (DFS(map, 7, 8, st, i, j - 1))
			return true;
	map[i][j] = 0;
	st.pop();
	return false;
}
int main()
{
	int map[7][8] = {
		{0,0,0,1,1,1,1,1},
		{0,1,0,1,1,1,1,1},
		{0,1,0,1,0,0,0,1},
		{0,1,0,1,0,1,0,1},
		{0,1,0,0,0,1,0,1},
		{0,1,1,1,1,1,0,1},
		{0,0,0,0,0,0,0,0}
	};
	//vector<path> res = BFS(map, 7, 8);
	//int i = res.size() - 1;
	/*while (i >= 0)
	{
		cout << "(" << res[i]._x << "," << res[i]._y << ")" << endl;
		i = res[i]._prev;
	}*/
	//Print(res, i);
	stack<_path> st;
	DFS(map, 7, 8, st, 0, 0);
	while (!st.empty())
	{
		cout << "(" << st.top()._x << "," << st.top()._y << ")" << endl;
		st.pop();
	}
}

🚀运行结果
在这里插入图片描述

可以返现这个路径仍然是从终点到起点的,所以如果想要正序输出那么仍然要做修正。
但是还要注意的是,迷宫中有两条路径,栈中只记录了一条路径,恰巧这个路径是最短路径,注意这是恰巧,这和你第一步的走向有关。如果你改变走向结果也可能会变,所以DFS并不适合求最短路径,但是用来求路径还是没毛病的。

bool DFS(int map[][8], int row, int col, stack<_path>& st,int i,int j)
{
	st.push(_path(i, j));
	map[i][j] = -1;
	if (i == row - 1 && j == col - 1)
		return true;
	if (check(i, j + 1, map, 7, 8)) //先向右走
		if (DFS(map, 7, 8, st, i, j + 1))
			return true;
	if (check(i + 1, j, map, 7, 8))
		if (DFS(map, 7, 8, st, i + 1, j))
			return true;
	if (check(i - 1, j, map, 7, 8))
		if (DFS(map, 7, 8, st, i - 1, j))
			return true;
	if (check(i, j - 1, map, 7, 8))
		if (DFS(map, 7, 8, st, i, j - 1))
			return true;
	map[i][j] = 0;
	st.pop();
	return false;
}

在这里插入图片描述
🚀可以看到先向右走的时候,栈中存储的数据就是另一条路径了,这也验证了DFS不适合求最短路径。注意我说的是不适合不代表DFS不能求最短路径。

DFS解决迷宫所有路径问题

🚀思路

求所有路径,我们可以使用vector,每一步都记录在vector中,如果当前位置到达了终点,那么就打印vector中的路径。

🚀代码

void DFS2(int map[][8], int row, int col, int i, int j, vector<_path> v)
{
	v.push_back(_path(i, j));
	map[i][j] = -1;
	if (i == row - 1 && j == col - 1)
	{
		for (int i = 0; i < v.size(); i++)
		{
			cout << "(" << v[i]._x << "," << v[i]._y << ")" << endl;
		}
		cout << "-------------------------------" << endl;
	}
	if (check(i, j + 1, map, 7, 8)) //先向右走
		DFS2(map, 7, 8, i, j + 1,v);
	if (check(i + 1, j, map, 7, 8))
		DFS2(map, 7, 8,  i + 1, j, v);
	if (check(i - 1, j, map, 7, 8))
		DFS2(map, 7, 8,  i - 1, j,v);
	if (check(i, j - 1, map, 7, 8))
		DFS2(map, 7, 8,  i, j - 1,v);
	map[i][j] = 0;
}

🚀结果展示
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Jmeter和Testlink自动化测试框架研究与实施

摘 要 目前基于Jmeter的接口自动化测试框架&#xff0c;大多只实现脚本维护和自动调度&#xff0c;无法与Testlink进行互通&#xff0c;实现测试方案与自动化实施流程连接&#xff0c;本文基于Testlink、Jmeter、Jenkins实现&#xff1a;通过Testlink统一维护接口自动化测试用…

搭建es集群

单点es的缺点&#xff1a;1.存储数据有限&#xff1b;2.单点故障问题&#xff08;es出现故障则整个服务会直接宕机&#xff09; 解决存储数据有限&#xff1a;搭建多台es服务器实现集群 解决单点故障&#xff1a;在不同的es服务器中进行备份数据&#xff08;例&#xff1a;在…

车载测试需要有哪些知识需要学习的?

一、车载行业前景 其中的车载测试也随着国家对新能源、智能驾驶等领域的支持&#xff0c;而异常活跃&#xff0c;目前我国共有9000家自动驾驶相关企业&#xff0c;而今年从华为、中兴、大唐等通信领域的企业到以阿里、腾讯、小米等为代表的互联网企业&#xff0c;均已布局自动…

浅谈继承和发扬传统文化路径

中华民族五千年文明历史,造就了博大精深的中华传统文化。如何继承和发扬传统文化,是当代文化爱好者和工作者所关注的&#xff0c;实现这一使命,文化传承需要在以下路径上发力: 1. “微更新”路径。在传承的基础上进行融合拓展,实现内涵丰富和更新。 2. “强保护”路径。利用立…

空压机远程监控系统解决方案

一、项目背景 随着物联网各种技术快速发展,各物联网远程监测应用场景也应用而生&#xff0c;空压机是一种空气压缩和气体输送设备&#xff0c;广泛运用于矿山、机械、电子、医疗等各行业。空压机常规都是需要人在现场监测和维护,现在通过物联网技术,远程监控成为可能&#xff…

利用Msray-plus提升SEO工作效率和效果

随着互联网的不断发展和普及&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;已经成为了网站推广和营销的重要手段之一。SEO的核心是通过优化网站的结构、内容和关键词等&#xff0c;提高网站在搜索引擎中的排名&#xff0c;从而吸引更多的访问量和潜在客户。然而&#xf…

多通道振弦传感器无线采集采集仪如何开始使用

多通道振弦传感器无线采集采集仪如何开始使用 开始使用 设备电源 VS208~432 可使用内置电池&#xff08;默认&#xff09;也可使用外部电池工作。 需要特别注意&#xff1a;严禁内置和外部电池&#xff08;电源&#xff09;同时使用&#xff0c;严重时会造成短路起火&#xff0…

宝塔搭建chevereto图床

前言 chevereto是一个国外开发的图床&#xff0c;使用phpnginxmysql搭建的&#xff0c;使用宝塔面板更方便搭建chevereto图床&#xff0c;chevereto有收费和免费版本 准备环境 宝塔面板&#xff0c;百度网上很多教程&#xff0c;一键安装.chevereto安装包&#xff0c;本次使…

Cadence Allegro PCB设计88问解析(二十七) 之 Allegro中dimension environment命令使用(添加及删除尺寸标注)

一个学习信号完整性仿真的layout工程师 在通常的设计中&#xff0c;一般会在outline的光绘层中添加单板或则拼版外形的尺寸大小。方便板厂人员查看&#xff0c;但是尺寸标注的添加涉及到尺寸单位、精度等&#xff0c;要根据公司的标准添加。如果需要修改尺寸的参数&#xff0c;…

nssctf web 入门(7)

这里通过nssctf的题单web安全入门来写&#xff0c;会按照题单详细解释每题。题单在NSSCTF中。 想入门ctfweb的可以看这个系列&#xff0c;之后会一直出这个题单的解析&#xff0c;题目一共有28题&#xff0c;打算写10篇。 [SWPUCTF 2021 新生赛]hardrce [SWPUCTF 2021 新生赛…

【快乐手撕LeetCode题解系列】——环形链表

【【快乐手撕LeetCode题解系列】——移除链表元素&#x1f60e;前言&#x1f64c;环形链表&#x1f64c;画图分析&#xff1a;&#x1f60d;思路分析&#xff1a;&#x1f60d;源代码分享&#xff1a;&#x1f60d;总结撒花&#x1f49e;&#x1f60e;博客昵称&#xff1a;博客…

python简单认识一下字面量并尝试编写输出字面量在控制台

首先 还是顾名思义 什么是字面量&#xff1f; 在代码中写下来的固定的值 我们称之为 字面量 python的字面量主要是以下几种 当然 前期不需要那么急 我们先熟悉 数字类型中的 整数 浮点数 和字符串类型 然后后续再慢慢扩展即可 整数呢 就相当于 我们数学中的 正整数 例如 1 10…

Compose (10/N) - 动画

一、高级别动画 1.1 简单值动画 animate***AsState 为单个值添加动画。只需要指定目标值&#xff0c;会从当前值向目标值渐变。 animateColorAsStateanimateDpAsStateanimateSizeAsStateanimateOffsetAsStateanimateRectAsState animateIntAsState animateIntOffsetAsState an…

【机会约束、鲁棒优化】机会约束和鲁棒优化研究优化【ccDCOPF】研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【数据挖掘与商务智能决策】第十章 支持向量机

1. 线性可分SVM import numpy as np import pandas as pd import matplotlib.pyplot as plt%matplotlib inline1.1 生成模拟数据 # 导入sklearn模拟二分类数据生成模块 from sklearn.datasets import make_blobs # 生成模拟二分类数据集 X, y make_blobs(n_samples150, n_f…

SIP协议之RTP负载类型(payload type)

一、RTP负载类型介绍​ 在SIP 音视频通话中&#xff0c;媒体数据是由RTP包携带的&#xff0c; RTP包中的PT字段标识了负载媒体数据的类型。如下图&#xff1a; 注&#xff1a; PT表示负载类型(Payload Type), 7 bits&#xff0c;即所传输的多媒体的类型 ​  不同的媒体编码…

Kafka消费者组和分区再均衡

应用程序使用KafkaConsumer向Kafka订阅主题&#xff0c;并从订阅的Topic上接收消息。 要想知道如何从Kafka读取消息&#xff0c;需要先了解消费者和消费者组的概念。 1、消费者和消费者组 原因&#xff1a;假设我们有一个应用程序需要从一个Kafka Topic中读取消息并验证&…

14Exceptional Control Flow Exceptions and Process(异常控制流,异常和进程)

异常控制流 异常控制流出现的地方&#xff1a; 异常控制流&#xff08;Exceptional Control Flow&#xff0c;ECF&#xff09;是程序执行过程中由于某些特殊事件或条件而导致的控制流的改变。异常控制流通常出现在以下几种情况&#xff1a; 硬件异常和中断&#xff1a;硬件异…

14天手撸交互式问答数字人直播教程-课程计划

一、课程计划 二、时间安排 第01天&#xff1a;交互式问答数字人发展现状 从一个真实案例开始&#xff0c;介绍当前主流的交互式数字人平台&#xff0c;需求和应用场景&#xff0c;引入交互式数字人的交互流程和关键技术。后续整个直播系列的内容安排。 第02天&#xff1a;音…

Nvidia Orin刷机保姆级教程

文章目录前言一、刷机准备二、刷机实战1.刷机文件下载2.Orin进入刷机模式2.1拔掉Orin上所有线缆2.2插上type-c线缆2.3长按Force Recovery按钮2.4通电2.5松开2号按钮进入刷机模式2.6确认是否进入刷机模式3.命令行刷机3.1安装jetpack总结前言 使用Orin有段时间了&#xff0c;现在…