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

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

相关文章

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动

深入浅出Spring中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired

PostgreSQL简介及实战应用

《PostgreSQL简介及实战应用》PostgreSQL是一种功能强大的开源关系型数据库管理系统,以其稳定性、高性能、扩展性和复杂查询能力在众多项目中得到广泛应用,本文将从基础概念讲起,逐步深入到高... 目录前言1. PostgreSQL基础1.1 PostgreSQL简介1.2 基础语法1.3 数据库

Python中的filter() 函数的工作原理及应用技巧

《Python中的filter()函数的工作原理及应用技巧》Python的filter()函数用于筛选序列元素,返回迭代器,适合函数式编程,相比列表推导式,内存更优,尤其适用于大数据集,结合lamb... 目录前言一、基本概念基本语法二、使用方式1. 使用 lambda 函数2. 使用普通函数3. 使用 N

Python中yield的用法和实际应用示例

《Python中yield的用法和实际应用示例》在Python中,yield关键字主要用于生成器函数(generatorfunctions)中,其目的是使函数能够像迭代器一样工作,即可以被遍历,但不会... 目录python中yield的用法详解一、引言二、yield的基本用法1、yield与生成器2、yi

Python多线程应用中的卡死问题优化方案指南

《Python多线程应用中的卡死问题优化方案指南》在利用Python语言开发某查询软件时,遇到了点击搜索按钮后软件卡死的问题,本文将简单分析一下出现的原因以及对应的优化方案,希望对大家有所帮助... 目录问题描述优化方案1. 网络请求优化2. 多线程架构优化3. 全局异常处理4. 配置管理优化优化效果1.

从基础到高阶详解Python多态实战应用指南

《从基础到高阶详解Python多态实战应用指南》这篇文章主要从基础到高阶为大家详细介绍Python中多态的相关应用与技巧,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、多态的本质:python的“鸭子类型”哲学二、多态的三大实战场景场景1:数据处理管道——统一处理不同数据格式

Java Stream 的 Collectors.toMap高级应用与最佳实践

《JavaStream的Collectors.toMap高级应用与最佳实践》文章讲解JavaStreamAPI中Collectors.toMap的使用,涵盖基础语法、键冲突处理、自定义Map... 目录一、基础用法回顾二、处理键冲突三、自定义 Map 实现类型四、处理 null 值五、复杂值类型转换六、处理

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

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

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