图的导航-最短路径算法-深度优先遍历

news2024/10/5 16:50:27

介绍

最短路径:从起点开始访问所有的路径,到达终点的路径有多条,其中路径的权值最短的一条则为最短路径。

最短路径算法有深度优先遍历、广度优先遍历、Bellman-Ford算法、弗洛伊德算法、SPFA算法、迪杰斯特拉算法等。

而本篇讲的是利用深度优先遍历(DSF)求最短路径。

深度优先遍历(DSF)

先来看下面的例子,起点为A,终点为E。

8be62bc0c8d046c88803b743b2a55aa8.png

A-C-E 路径是最短的,权值为13。

首先从 A 出发,有三个分支,先选择一个分支D,将D设置为访问过的状态(避免重复访问),同时保存路径D,从D出发有一个分支E,将E设置为访问过的状态,保存路径E,到达E,E为终点,所以找到了一条可行路径,将它的权值和最小权值比较,如果小于就更新最小权值,同时有一个数组保存最短路径,将这条可行路径拷贝到数组里。

然后沿路返回将E、D设置为未被访问的状态,同时在路径中删除E、D,回到起点A选择分支C,将C设为访问过的状态并且保存C,C有一个分支E,将E设为访问过的状态并且保存,此时E为终点,找到一条可行路径,将它的权值和最小权值比较,如果小于就更新最小权值,同时有一个数组保存最短路径,将这条可行路径拷贝到数组里。

……

主要用到了递归的思想。

核心代码部分

int min_weight = 0x7FFFFFFF; //最短路径的权重
int min_path[MaxSize] = { 0 };// 最短的路径

int steps; //已走过的步数
int path[MaxSize] = { 0 }; //保存当前走的这条路径


/*深度遍历求解从起点到终点的最短路径*/
void DFS(AdjListGraph& G, int start,int end,int weights) //weights是前面已走的路径累计的权重
{
	visited[start] = true; //访问状态设为true

	if (start == end) //如果起点就是终点,递归结束
	{
		for (int i = 0; i < steps; i++)
		{
			cout << G.adjlist[path[i]].date << " "; //打印一条可行的路径
		}
		cout << "该路径的长度为:" << weights << endl;

		if (min_weight > weights) //找到了一条更短的路径,更新最短路径
		{
			min_weight = weights;
			memcpy(min_path, path, steps * sizeof(int));
		}
	}

	EdgeNode* tmp = G.adjlist[start].first;
	int weight = 0; //下一个要访问的节点的权重
	int cur = -1;//下一个要访问的节点的位置

	while (tmp)
	{
		cur = tmp->adjvex;
		weight = tmp->weight;

		if (visited[cur] == false)
		{
			visited[cur] = true; 
			path[steps++] = cur; //保存路径

			DFS(G, cur, end, weights + weight);

			visited[cur] = false; //还原状态
			path[--steps] = 0;
		}

		tmp = tmp->next;
	}

}

建议先看递归未结束的代码。 

所有的代码以及测试样例

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





//利用深度优先遍历求最短路径算法


#define MaxSize 1024
typedef char DateElem;

//边
typedef struct _EdgeNode
{
	int adjvex;		//与之相邻的节点在数组中的位置
	int weight;		//边的权重
	struct _EdgeNode* next; //指向下一条相邻的边
}EdgeNode;

//顶点
typedef struct _VertexNode
{
	DateElem date;				//顶点的数据
	struct _EdgeNode* first;	//指向第一条与之相邻的边
}VertexNode, AdjList;

//邻接链表 
typedef struct _AdjListGraph
{
	AdjList* adjlist; //数组,保存着所有的顶点
	int vex;	//顶点数
	int edge;	//边数
}AdjListGraph;



bool visited[MaxSize]; //节点是否被访问过,被访问过设为true
//图的初始化
void Init(AdjListGraph& G)
{
	G.adjlist = new AdjList[MaxSize];
	G.edge = 0;
	G.vex = 0;

	for (int i = 0; i < MaxSize; i++)
	{
		visited[i] = false;
	}
}


int Location(AdjListGraph& G, DateElem c);
//图的创建
void Create(AdjListGraph& G)
{
	cout << "请输入顶点的个数和边的个数:" << endl;
	cin >> G.vex >> G.edge;

	cout << "请依次输入顶点的数据:" << endl;

	for (int i = 0; i < G.vex; i++)
	{
		cin >> G.adjlist[i].date;
		G.adjlist[i].first = NULL;
	}


	cout << "请依次输入边以及它的权重:" << endl;
	DateElem v1, v2;
	int weight = 0;
	int i1 = 0, i2 = 0;

	for (int i = 0; i < G.edge; i++)
	{
		cin >> v1 >> v2;
		cin >> weight;

		i1 = Location(G, v1);
		i2 = Location(G, v2);

		if (i1 != -1 && i2 != -1) //确保两个顶点存在
		{
			EdgeNode* tmp = new EdgeNode;
			tmp->adjvex = i2;
			tmp->weight = weight;
			tmp->next = G.adjlist[i1].first; //头插
			G.adjlist[i1].first = tmp;
		}
	}
}

/*通过顶点保存的数据找到顶点在图中的位置*/
int Location(AdjListGraph& G, DateElem c)
{

	for (int i = 0; i < G.vex; i++)
	{
		if (G.adjlist[i].date == c)
		{
			return i;
		}
	}

	return -1; //没找到
}


int min_weight = 0x7FFFFFFF; //最短路径的权重,初始化为int类型中最大的整数
int steps; //已走过的步数
int path[MaxSize] = { 0 }; //保存当前走的这条路径
int min_path[MaxSize] = { 0 };// 最短的路径

/*深度遍历求解从起点到终点的最短路径*/
void DFS(AdjListGraph& G, int start,int end,int weights) //weights是前面的路径累计的权重
{
	visited[start] = true; //访问设为true

	if (start == end) //如果起点就是终点
	{
		for (int i = 0; i < steps; i++)
		{
			cout << G.adjlist[path[i]].date << " "; //一条可能的路径
		}

		cout << "该路径的长度为:" << weights << endl;

		if (min_weight > weights) //找到了一条更短的路径,更新最短路径
		{
			min_weight = weights;
			memcpy(min_path, path, steps * sizeof(int));
		}
	}

	EdgeNode* tmp = G.adjlist[start].first;
	int weight = 0; //下一个要访问的节点的权重
	int cur = -1;//下一个要访问的节点的位置

	while (tmp)
	{
		cur = tmp->adjvex;
		weight = tmp->weight;
		if (visited[cur] == false)
		{
			visited[cur] = true; 
			path[steps++] = cur; 
			DFS(G, cur, end, weights + weight);

			visited[cur] = false; //上一个路线的顶点设为未被访问的状态
			path[--steps] = 0;
		}

		tmp = tmp->next;
	}

}



int main(void)
{
	AdjListGraph G;

	//图的初始化
	Init(G);

	//图的创建
	Create(G);
	/*  A B 12
		A C 8
		A E 10
		B D 13
		C D 5
		E D 10	*/


	DateElem start, end;
	cout << "请输入路径的起点和终点:" << endl;
	cin >> start >> end;

	
	DFS(G, Location(G, start), Location(G, end), 0);

	cout << "最短路径长度为:" << min_weight <<  endl;
	
	int i = 0;
	cout << "最短路径为:";
	while (i < MaxSize && min_path[i] != 0)
	{
		cout << G.adjlist[min_path[i]].date << " ";
		i++;
	}

	return 0;
}

85d797499f564f53a79eeaf150bfd1fa.png

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

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

相关文章

TypeScript中的基本类型

提示&#xff1a;TypeScript中的基本类型 文章目录 前言基本类型1.类型声明2.自动类型判断3.类型断言 前言 TypeScript &#xff08;计算机编程语言&#xff09;简称&#xff1a;TS&#xff0c;是 JavaScript 的超集。简单来说就是&#xff1a;JS 有的 TS 都有。JS写的代码在TS…

基于ssm民宿管理系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本民宿管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息&am…

H5 - - - - 移动端禁止长按保存图片

H5 - - - - 移动端禁止长按保存图片 1. 问题描述2. 解决办法2.1 img标签添加css属性2.2 设置为背景图片2.3 图片元素的同级加一个透明盒子 1. 问题描述 H5移动端 img标签长按&#xff0c;会出现如图效果⬇️ 那么该如何修改&#xff0c;能避免长按保存图片操作呢&#xff1f; …

代码随想Day36 | 435. 无重叠区间、763.划分字母区间、56. 合并区间

435. 无重叠区间 这道题和前一天的射箭题目思想类似&#xff0c;用总区间个数-不重叠的区间个数等于需要去除的区间个数。首先对左边界排序&#xff0c;如果当前的左边界大于等于上一区间的右边界&#xff0c;则说明是一个不重叠的区间&#xff0c;否则&#xff0c;更新上一重…

Microsoft 发布了 12 月份产品安全问题修复报告。

&#x1f525; Microsoft 发布了 12 月份产品安全问题修复报告。 请注意趋势漏洞 CVE-2023-36011 和 CVE-2023-35632。这些漏洞与 Win32k 内核和负责网络通信的辅助功能驱动程序 (AFD) 驱动程序中的缺陷有关。成功利用这两个漏洞可让进入 Windows 系统的攻击者将其权限提升至系…

NXP应用随记(二):S32K3xx内存随记

目录 1、TCM 1.1、代码放置在ITCM的方式 __attribute__ 的函数属性 __attribute__ 的变量属性 __attribute__ 的类型属性 __attribute__ 的优化控制属性 1.2、DTCM 1.3、TCM的使用注意事项 1、TCM CMTightly Coupled Memory&#xff0c;是一种高速缓存&#xff0c;据说是…

【EI会议征稿】第三届电力系统与电力工程国际学术会议(PSPE 2024)

第三届电力系统与电力工程国际学术会议&#xff08;PSPE 2024&#xff09; 2024 3rd International Conference on Power System and Power Engineering(PSPE 2024) 第三届电力系统与电力工程国际学术会议&#xff08;PSPE 2024&#xff09;于2024年3月29-31日在中国三亚隆重召…

开发案例:使用canvas实现图表系列之折线图

一、功能结构 实现一个公共组件的时候&#xff0c;首先分析一下大概的实现结构以及开发思路&#xff0c;方便我们少走弯路&#xff0c;也可以使组件更加容易拓展&#xff0c;维护性更强。然后我会把功能逐个拆开来讲&#xff0c;这样大家才能学习到更详细的内容。下面简单阐述…

C++怎么快速提升实力?

C怎么快速提升实力&#xff1f; 在开始前我有一些资料&#xff0c;是我根据自己从业十年经验&#xff0c;熬夜搞了几个通宵&#xff0c;精心整理了一份「C的资料从专业入门到高级教程工具包」&#xff0c;点个关注&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&…

redis-学习笔记(Jedis hash简单命令)

hset & hget 往 hash 里面塞数据和获取数据 示例代码 hmset & hmget 批量插入数据, 获取数据 注意, hmset 里面插入的是一个 Map hmget 的返回值是一个一个 List 列表 (参数仍是变长参数) 示例代码 hexists 判断 hash 中 域值 存不存在 示例代码 hdel 删除指定的域和值…

SpringBoot 引入nacos 【最新 | 可运行】

SpringBoot 引入nacos 首先要了解在 Springboot 中只支持那些 Springboot 的版本&#xff08;我真的被这个搞死了&#xff09;,可以如下图参考&#xff1a; 下面我们就开始吧 下载 Nacos nacos 下载地址&#xff0c;这里可以选择你要下载的版本&#xff0c;我选择下载了2.2.…

基于Java8构建Docke镜像

基于Java8构建Docke镜像 搜索java8安装包 docker search java8 --no-trunc &#xff0c; --no-trunc展开描述信息 选择拉取 docker pull docker.io/mykro/java8-jre&#xff0c;为了减少磁盘占用&#xff0c;选择jre版本基础镜像 在宿主机创建文件夹iot&#xff0c;并把所需…

【FPGA/verilog -入门学习4】verilog 实现多路脉冲计数

需求&#xff1a; 设计一个脉冲计数器&#xff0c;其功能如下 输入脉冲&#xff1a;4路脉冲信号&#xff0c;分别对每路进行脉冲检测并计数 使能信号&#xff1a;高电平进行计数&#xff0c;低电平清零计数器 计数器&#xff1a;在使能信号高电平期间&#xff0c;对脉冲信号…

Kubernetes版本升级到v1.18.0方法

升级k8s版本才能使用kube-prometheus安装监控 1、查看集群状态 [rootk8s-master k8s-script]# kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-master Ready master 5d22h v1.18.0 k8s-slave1 Ready <none> 4d10h v1.18.0 k…

Tomcat部署Activiti官方 流程设计器【数据库更换为Mysql !!!】

一、官网下载activiti6 解压后结构如下: database&#xff1a; 存放数据库对象相关脚本&#xff0c;包含不同的数据库脚本 libs&#xff1a; 包含activiti开发过程中需要用到的jar包和源码&#xff0c;不建议通过jar包直接引用&#xff0c;建议通过maven进行管理 wars&am…

opencv 十五 红外图像中虹膜的提取

一、算法需求 在医疗检测中&#xff0c;需要使用红外相机拍摄眼睛照片&#xff0c;然后提取出虹膜的区域。在拍摄过程瞳孔需要进行运动&#xff0c;其通常不在正前方&#xff0c;无法形成圆形&#xff0c;不能使用常规的霍夫圆检测进行提取定位。且在在红外图像中&#xff0c;…

数据结构和算法 - 前置扫盲

数据结构和算法 一、前置扫盲 1、数据结构分类 1.1 逻辑结构&#xff1a;线性与非线性 tip&#xff1a;逻辑结构揭示了数据元素之间的逻辑关系。 线性数据结构&#xff1a;元素间存在明确的顺序关系。 数据按照一定顺序排列&#xff0c;其中元素之间存在一个对应关系&#x…

第二百零四回 模拟对话窗口的页面

文章目录 1. 概念介绍2. 思路与方法2.1 实现思路2.2 实现方法 3. 示例代码4. 经验分享5. 内容总结 我们在上一章回中介绍了"修改组件风格的另外一种方法"相关的内容&#xff0c;本章回中将介绍" 如何做一个模拟对话框窗口的页面".闲话休提&#xff0c;让我…

PCL点云处理之判断某一点在三角形的内部、外部、还是边上(二百二十二)

PCL点云处理之判断某一点在三角形的内部、外部、还是边上(二百二十二) 一、算法介绍二、算法实现1.代码2.结果一、算法介绍 点与三角形的位置共有三种: 1 内部 2 外部 3 点刚好在边上 (这个判断还是很有必要的,应用广泛,下面代码复制粘贴即可使用,纯C++实现) 二、算…

模块一——双指针:18.四数之和

文章目录 题目描述算法原理排序双指针 代码实现排序双指针复杂度分析时间复杂度&#xff1a;O(N^3^)空间复杂度&#xff1a;O(log⁡N)或者O(N) 题目描述 题目链接&#xff1a;18.四数之和 算法原理 排序双指针 依次固定⼀个数a &#xff1b;在这个数a 的后⾯区间上&#x…