第六章 图(下)【图的应用,重难点】

2023-11-20 22:15
文章标签 应用 第六章 重难点

本文主要是介绍第六章 图(下)【图的应用,重难点】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 最小生成树

 1.1 最小生成树的概念

  • 生成树:连通图的生成树是包含图中全部顶点的一个极小连通子图。 若图中顶点数为 n,则它的生成树含有 n-1 条边。对生成树而言,若砍去它的一条边,则会变成非连通图,若加上一条边则会形成一个回路。

  • 最⼩⽣成树(最⼩代价树):对于一个带权连通无向图G =(V,E),生成树不同,每棵树的权(即树中所有边上的权值之和)也可能不同。设R为G的所有生成树的集合,若T为R中边的权值之和最小的生成树,则T称为G的最小生成树(Minimum-Spannino-Tree,MST).。
  • 最小生成树可能有多个,但边的权值之和总是唯一且最小的。
  • 最小生成树的边数 =顶点数 -1。砍掉一条则不连通,增加一条边则会出现回路。
  • 如果一个连通图本身就是一棵树,则其最小生成树就是它本身。
  • 只有连通图才有生成树,非连通图只有生成森林。

 求最小生成树的两种方法

1.2 Prim算法(普里姆)

从某一个顶点开始构建生成树;每次将代价最小的新顶点纳入生成树,直到所有顶点都纳入为止。时间复杂度: O(V2)适合用于边稠密图。核心思想:贪心算法

同一顶点开始生成的最小生成树可能也不一样,但是最小代价是一样的

 

算法实现:

Prim 算法的实现思想:

1.初始:从V0开始,标记各节点是 否已加⼊树isJoin,各节点加⼊树 的最低代价,lowCost

2.  第1轮:循环遍历所有个结点,找 到lowCost最低的,且还没加⼊树 的顶点将该顶点加入树,再次循环遍历,更新还没加⼊的 各个顶点的lowCost值

3. 重复1,2,从V0开始,总共需要 n-1 轮处理,每⼀轮处理:循环遍历所有个结 点,找到lowCost最低的,且还没 加⼊树的顶点。 再次循环遍历,更新还没加⼊的 各个顶点的lowCost值,

每⼀轮时间复 杂度O(2n),总时间复杂度 O(n2),即O(|V|2)

void Prim(G, T)
{// T为空;// U = {w};while((V-U)! = NULL){设(u,v)为让u属于U,v属于(V-U)对最短边T = T U {(u,v)};    //边入树U = U U {v};        //顶点入树}
}//辅助数组:
isJoin[vexNum];    //标记各节点是否已加入树
lowCost[vexNum];    //各节点加入树的最小代价 != 权值,每次并入新节点后都需要更新

1.3 Kruskal算法(克鲁斯卡尔)

每次选择一条权值最小的边,使这条边的两头连通(原本已经连通的就不选)直到所有结点都连通。时间复杂度: O(|E|log|E|)适合用于边稀疏图。

算法实现:

 1. 初始:将各条边按权值排序

2.第1轮:检查第1条边的两个顶点是否 连通(是否属于同⼀个集合) 不连通,则连起来

2.第i轮:检查第i条边的两个顶点是否 连通(是否属于同⼀个集合)不连通,则连起来,已连通,则跳过

共执⾏ e 轮,每轮判断两个顶点是 否属于同⼀集合,需要 O(log2e) 总时间复杂度 O(elog2e)

void Kruskal(v, T)
{T = v;numS = n;    //连通分量数while(numS>1){从E中选取权值最小的边(u,v);if(v和u属于不同连通分量){T = T U {(v,u)};    //边入树numS--;}}
}

2. 最短路径问题

2.1 无权图的单源最短路径问题——BFS算法

 ⽆权图可以视为⼀种特殊的带权图,只是每条边的权值都为1

从2出发寻找无权图的单源最短路径

算法实现:

使用 BFS算法求无权图的最短路径问题,需要使用三个数组

  • d[]数组用于记录顶点 u 到其他顶点的最短路径。
  • path[]数组用于记录最短路径从那个顶点过来。

  • visited[]数组用于记录是否被访问过。

在visit⼀个顶点时,修改其最短路径⻓度 d[ ] 并在 path[ ] 记录前驱结点

代码实现:

#define MAX_LENGTH 2147483647			//地图中最大距离,表示正无穷// 求顶点u到其他顶点的最短路径
void BFS_MIN_Disrance(Graph G,int u){for(i=0; i<G.vexnum; i++){visited[i]=FALSE;				//初始化访问标记数组d[i]=MAX_LENGTH;				//初始化路径长度path[i]=-1;						//初始化最短路径记录}InitQueue(Q);						//初始化辅助队列d[u]=0;visites[u]=TRUE;EnQueue(Q,u);while(!isEmpty[Q]){					//BFS算法主过程DeQueue(Q,u);					//队头元素出队并赋给ufor(w=FirstNeighbor(G,u);w>=0;w=NextNeighbor(G,u,w)){if(!visited[w]){d[w]=d[u]+1;path[w]=u;visited[w]=TRUE;EnQueue(Q,w);			//顶点w入队}}}
}

2.2 带权图的单源最短路径问题——Dijkstra算法

相关概念背景

带权路径⻓度——当图是带权图时,⼀条路径上所有边的权值之和,称为该路径的带权路径⻓度

  1. BFS算法的局限性:BFS算法求单源最短路径只适⽤于⽆权图,或所有边的权值都相同的图。
  2. Dijkstra算法能够很好的处理带权图的单源最短路径问题,但不适⽤于有负权值的带权图。

算法实现:

使用 Dijkstra算法求最短路径问题,需要使用三个数组:

  • final[]数组用于标记各顶点是否已找到最短路径。
  • dist[]数组用于记录各顶点到源顶点的最短路径长度。
  • path[]数组用于记录各顶点现在最短路径上的前驱。

 1. 初始:从V0开始,初始化三个数组信息

2. 第1轮:循环遍历所有结点,找到还没确定最短 路径,且dist 最⼩的顶点Vi,令final[i]=ture,检查所有邻接⾃ Vi 的顶点,若其 final 值为false, 则更新 dist 和 path 信息

 ​​​​​​

3.重复过程2,n-1轮处理,直到所有顶点的final 值为true.并更新完成

4.  使⽤数组信息

代码实现:

#define MAX_LENGTH = 2147483647;// 求顶点u到其他顶点的最短路径
void BFS_MIN_Disrance(Graph G,int u){for(int i=0; i<G.vexnum; i++){		//初始化数组final[i]=FALSE;dist[i]=G.edge[u][i];if(G.edge[u][i]==MAX_LENGTH || G.edge[u][i] == 0)path[i]=-1;elsepath[i]=u;final[u]=TREE;}for(int i=0; i<G.vexnum; i++){int MIN=MAX_LENGTH;int v;// 循环遍历所有结点,找到还没确定最短路径,且dist最⼩的顶点vfor(int j=0; j<G.vexnum; j++){if(final[j]!=TREE && dist[j]<MIN){MIN = dist[j];v = j;}}final[v]=TREE;// 检查所有邻接⾃v的顶点路径长度是否最短for(int j=0; j<G.vexnum; j++){if(final[j]!=TREE && dist[j]>dist[v]+G.edge[v][j]){dist[j] = dist[v]+G.edge[v][j];path[j] = v;}}}
}

 时间复杂度: O(n2)即O(|V|2)

2.3 各顶点间的最短路径问题——Floyd算法 

2.3.1 Floyd算法基本思想:

求出每⼀对顶点之间的最短路径,使⽤动态规划思想,将问题的求解分为多个阶段。

 

2.3.2 Floyd算法应用范围

可以⽤于负权值带权图,但是不能解决带有“负权回路”的图(有负权值的边组成回路),这种图有可能没有最短路径。

 算法实现:

  1. Floyd算法使用到两个矩阵:

    1. dist[][]:目前各顶点间的最短路径。
    2. path[][]:两个顶点之间的中转点。

 

递推一个n阶方阵序列A^{-1}A^{0},...,A^{k},...,A^{n-1},其中A^{k}[i][j]表示从顶点vi到vj的长度,k表示绕行第k个顶点的运算步骤,利用path^{k}记录节点的中转情况。 

 步骤:①初始时若v0到vi之间有边,则记录其最短路径为该边权值,若不存在则记∞

            ②尝试允许经过v0顶点中转,更新顶点间最短路径

            ③依此尝试允许经过v1,v2,...,vk顶点中转,并不断更新最短路径,,直到允许v(n-1)顶点都经过中转,方阵 [i][j] = Min{[i][j] , [i][k]+[k][j]}

            ④经过n次迭代,最终[i][j]就是vi到vj的最短路径长度

 代码实现:

//初始化矩阵A和path
...
for(int k=0; k<n; k++)
{for(int i=0; i<n; i++){for(int j=0; j<n; j++){if(A[i][j]>A[i][k]+A[k][j]){A[i][j] = A[i][k]+A[k][j];    //更新最短路径长度path[i][j] = k;               //中转点}}}
}

算法分析:时间复杂度——O(|V|^{3}),空间复杂度——O(|V|^{2})

这篇关于第六章 图(下)【图的应用,重难点】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/397813

相关文章

Python标准库之数据压缩和存档的应用详解

《Python标准库之数据压缩和存档的应用详解》在数据处理与存储领域,压缩和存档是提升效率的关键技术,Python标准库提供了一套完整的工具链,下面小编就来和大家简单介绍一下吧... 目录一、核心模块架构与设计哲学二、关键模块深度解析1.tarfile:专业级归档工具2.zipfile:跨平台归档首选3.

使用IDEA部署Docker应用指南分享

《使用IDEA部署Docker应用指南分享》本文介绍了使用IDEA部署Docker应用的四步流程:创建Dockerfile、配置IDEADocker连接、设置运行调试环境、构建运行镜像,并强调需准备本... 目录一、创建 dockerfile 配置文件二、配置 IDEA 的 Docker 连接三、配置 Do

深入浅出SpringBoot WebSocket构建实时应用全面指南

《深入浅出SpringBootWebSocket构建实时应用全面指南》WebSocket是一种在单个TCP连接上进行全双工通信的协议,这篇文章主要为大家详细介绍了SpringBoot如何集成WebS... 目录前言为什么需要 WebSocketWebSocket 是什么Spring Boot 如何简化 We

Java Stream流之GroupBy的用法及应用场景

《JavaStream流之GroupBy的用法及应用场景》本教程将详细介绍如何在Java中使用Stream流的groupby方法,包括基本用法和一些常见的实际应用场景,感兴趣的朋友一起看看吧... 目录Java Stream流之GroupBy的用法1. 前言2. 基础概念什么是 GroupBy?Stream

python中列表应用和扩展性实用详解

《python中列表应用和扩展性实用详解》文章介绍了Python列表的核心特性:有序数据集合,用[]定义,元素类型可不同,支持迭代、循环、切片,可执行增删改查、排序、推导式及嵌套操作,是常用的数据处理... 目录1、列表定义2、格式3、列表是可迭代对象4、列表的常见操作总结1、列表定义是处理一组有序项目的

C#中的Converter的具体应用

《C#中的Converter的具体应用》C#中的Converter提供了一种灵活的类型转换机制,本文详细介绍了Converter的基本概念、使用场景,具有一定的参考价值,感兴趣的可以了解一下... 目录Converter的基本概念1. Converter委托2. 使用场景布尔型转换示例示例1:简单的字符串到

Spring Boot Actuator应用监控与管理的详细步骤

《SpringBootActuator应用监控与管理的详细步骤》SpringBootActuator是SpringBoot的监控工具,提供健康检查、性能指标、日志管理等核心功能,支持自定义和扩展端... 目录一、 Spring Boot Actuator 概述二、 集成 Spring Boot Actuat

PyTorch中的词嵌入层(nn.Embedding)详解与实战应用示例

《PyTorch中的词嵌入层(nn.Embedding)详解与实战应用示例》词嵌入解决NLP维度灾难,捕捉语义关系,PyTorch的nn.Embedding模块提供灵活实现,支持参数配置、预训练及变长... 目录一、词嵌入(Word Embedding)简介为什么需要词嵌入?二、PyTorch中的nn.Em

Spring Boot3.0新特性全面解析与应用实战

《SpringBoot3.0新特性全面解析与应用实战》SpringBoot3.0作为Spring生态系统的一个重要里程碑,带来了众多令人兴奋的新特性和改进,本文将深入解析SpringBoot3.0的... 目录核心变化概览Java版本要求提升迁移至Jakarta EE重要新特性详解1. Native Ima

Redis中Stream详解及应用小结

《Redis中Stream详解及应用小结》RedisStreams是Redis5.0引入的新功能,提供了一种类似于传统消息队列的机制,但具有更高的灵活性和可扩展性,本文给大家介绍Redis中Strea... 目录1. Redis Stream 概述2. Redis Stream 的基本操作2.1. XADD