《算法导论》图相关算法小结

最近又抽空读了一遍《算法导论》,关于图的内容贯穿了多个章节(比如在动态规划一章埋了无权最短路径的伏笔,后面才专门讲),适用条件各异,而且都有证明过程。
如果不打算熟记证明,仅仅是应用,遇到具体场景再去回忆适用于哪种算法不太方便。

以下内容以手头的机械工业出版社基于原书第2版的译本整理了一下,便于速查。
不包含思考题、标注为“*”的章节和习题内容。

符号定义

一般地,
G=(V, E),其中V代表顶点集合,E代表集合。ω(u, v)代表从顶点u到顶点v的边的权值。
如果ω(u, v)总为1,则称G为不加权的图。

补充定义

  • DAG:有向无回路图
  • 拓扑排序:将DAG的节点按照一定规则输出:当有u到v的边,则u在v前面。
  • 强连通分支:对于图G(V, E),如果一个顶点集合C?G,其中每对顶点u和v,u和v相互都是可以到达的,那么称C是G的一个强连通分支
  • 最小生成树:无向连通图G的子集T,包含了所有顶点,且边的权值之和为最小。
  • 松弛技术:对于s顶点,d[v]表示s到v的距离。如果d[v] > d[u] + ω(u,v),则更新d[v] = d[u] + ω(u,v)
  • 最大流:对于包含源节点和汇节点的有向非负权图,最大的流量
  • 最大二分匹配:对于图G=(V,E),存在边的子集M?E,满足所有v∈V,M中最多有一条边与v关联。最大匹配是最大势的匹配,即不存在一个边数更多的M‘。

速查表

算法名称 适用范围 核心思想 基本步骤 时间复杂度 备注
广度优先搜索BFS 有向图/无向图,不涉及权重 1.队列 2.顶点按是否访问过着色 依次访问一个节点的所有相邻顶点,访问时着色并加入队列。每次循环从队列出队。 O(V+E) 可计算不加权的图最短路径
深度优先搜索DFS) 有向图/无向图,不涉及权重 1.递归 2.顶点按是否访问过着色 依次访问一个节点的所有相邻顶点,访问时着色并递归访问它的相邻顶点。 O(V+E)
拓扑排序(DFS) DAG DFS 执行DFS,当一个顶点DFS完成时插入链表头,这个链表就是拓扑排序结果 O(V+E)
计算强连通分支(DFS) DAG DFS 执行DFS,对图G倒置后按照节点访问次序的降序再计算一次DFS,第二次DFS的生成树即为强连通分支 O(V+E)
最小生成树-Kruskal算法 无向连通图 贪心算法 节点集合A初始化为空集,每次选一条安全边加入A。具体的,初始化每个节点都是一个集合,每次取最小权值的边,满足它的节点(u,v)所在集合不相等,此时令A=A∪{(u,v)} O(ElgV)
最小生成树-Prim算法 无向连通图 贪心算法 节点集合A初始化为空集,每次选一条安全边加入A。具体的,初始化所有节点距离A为正无穷,先在A加入一个节点,距离A为0。每次取一个离集合A中所有顶点中最近的边,加入它和它的顶点u,并将u的所有相邻节点v的距离更新一次(新距离=min(u到v, key(v))),直到所有顶点都加入了A O(ElgV),可以改进到O(E+VlgV)
单源最短路径-Bellman-Ford算法 有向图,权重可为负 松弛技术 松弛多次,次数为顶点数-1 O(VE) 如果有负权回路,返回值false。可用于差分约束问题求解。
单源最短路径-DAG DAG 拓朴排序、松弛技术 拓朴排序,按序取顶点,对它的所有临边松弛 O(V+E)
单源最短路径-Dijkstra算法 有向图,边权重非负 松弛技术 顶点集合S初始化为空集,加入源节点s。选取距离S整体最近的顶点u,松弛u的所有相邻顶点v,直到所有顶点都并入S O((V+E)lgV) 可以用斐波那契堆优化至O(VlgV+E)
每对顶点最短路径-Floyd-Warshall算法 有向图 动态规划 三重循环,k、i、j -> 1 to n, d(k)(i)(j) = min(d(k-1)(i)(j), d(k-1)(i)(k) + d(k-1)(j)(k)) O(n^3)
每对顶点最短路径-Johnson算法 有向图,稀疏图,边权重非负 重赋权,Dijkstra + Bellman-Ford 较为复杂,略 O(V^2lgV+VE)
最大流-Ford-Fulkerson方法 有向图,边权重非负,包含源节点和汇顶点 依赖三种思想及其对应实现 较为复杂,略 基本算法为O(E|f*|) 本书只介绍了基本算法、Edmods-Karp算法等。可用于解最大二分匹配问题

后注

每对顶点间最短路径也可以用Dijkstra和Bellman-Ford解决但不是最优,具体分析略。

附:图相关的NP完全问题

不详细介绍问题的含义。

  1. 团问题
  2. 顶点覆盖问题,在35章介绍了近似算法
  3. 哈密顿回路问题
  4. 旅行商问题,在35章介绍了近似算法

原文地址:https://www.cnblogs.com/wuyuegb2312/p/12390576.html

时间: 2024-10-07 05:02:12

《算法导论》图相关算法小结的相关文章

算法导论——lec 13 贪心算法与图上算法

之前我们介绍了用动态规划的方法来解决一些最优化的问题.但对于有些最优化问题来说,用动态规划就是"高射炮打蚊子",采用一些更加简单有效的方法就可以解决.贪心算法就是其中之一.贪心算法是使所做的选择看起来是当前最佳的,期望通过所做的局部最优选择来产生一个全局最优解. 一. 活动选择问题 [问题]对几个互相竞争的活动进行调度:活动集合S = {a1, a2, ..., an},它们都要求以独占的方式使用某一公共资源(如教室),每个活动ai有一个开始时间si和结束时间fi ,且0 ≤ si &

算法导论--图的遍历(DFS与BFS)

转载请注明出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51897538 图的遍历就是从图中的某个顶点出发,按某种方法对图中的所有顶点访问且仅访问一次.为了保证图中的顶点在遍历过程中仅访问一次,要为每一个顶点设置一个访问标志.通常有两种方法:深度优先搜索(DFS)和广度优先搜索(BFS).这两种算法对有向图与无向图均适用. 以下面无向图为例: 1.深度优先搜索(DFS) 基本步骤: 1.从图中某个顶点v0出发,首先访问v

算法导论--图的存储(邻接表与邻接矩阵)

转载请注明出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51888031 图的存储方法有邻接表.邻近矩阵.邻接多重表.十字链表等.本篇文章介绍两种简单且比较常用的两种方法:邻接表与邻接矩阵方法. 以下面的无向图为例,介绍两种存储方法.有向图的存储方法类似,只是边是单方向,无向图的边可以看做双向. 1.邻接链表法 邻接链表表示法对图中的每个顶点建立一个带头的边链表:第i条链表代表依附于顶点vi所有边信息,若为有向图,则表示

算法导论6:排序小结和最值取法 2016.1.6

今天想做测试各个排序算法运行时间比较的程序,来对这几天学的排序算法小结一下.所以我先生成了1000000个1~150之间的随机数存到文件里.然后做了一个测试运行时间的程序.想看一下结构.但是结果效果并不太好.实践中,自己做的qsort函数和mergesort函数并没有理想中的那么快. 结果是这样:(可能并不准确,但却是是运行结果) 库函数快速排序:0.139000 seconds自制快速排序:0.375000 seconds归并排序:0.358000 seconds堆排序:0.525000 se

算法导论之贪心算法

参考:http://www.cnblogs.com/Creator/archive/2011/06/07/2074227.html 贪心算法在几个基本算法里面算是相对简单的算法了,思路也是非常简单的,每一步总是做出在当前看来最好的选择.也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择.基本思路就是从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解.当达到某算法中的某一步不能再继续前进时,算法停止. 贪心算法存在的问题是: 1. 不能保证求得的最

图相关算法

1 图的表示 2 深度优先搜索 2.1 什么是深度优先搜索 2.2 深度优先搜索的应用案例 2.3 深度优先搜索的代码实现 3 广度优先搜索 3.1 什么是广度优先搜索 3.2 广度优先搜索的应用案例 3.3 广度优先搜索的代码实现 4 最小生成树 4.1 什么是最小生成树 4.2 最小生成树的应用案例 4.3 最小生成树的代码实现 5 拓扑排序 5.1 什么是拓扑排序 5.2 拓扑排序的应用案例 5.3 拓扑排序的实现

算法导论学习-prim算法

一. 关于最小生成树 对于无向连通图G=(V,E),其中V表示图的顶点,E表示图的边,对于每条边都有一个权值,可以理解为边a->b的权值C为从a走到b要走的路程为C.现在我们希望找到一个无回路的子集T,且有T是E的子集,T连接了所有的顶点,且其权值和最小.那么这样一个子图G‘=(V,T)称之为图G的最小生成树. 二. 最小生成树的基本性质 最小生成树的边数|T|必然服从|T|=|V|-1. 最小生成树不可以有循环 最小生成树不必是唯一的. 三. Prim算法 对于最小生成树有两种算法:prim算

【算法导论】贪心算法之赫夫曼编码

概述 讨论赫夫曼编码问题,赫夫曼编码的思想就是变长编码.变长编码就是让字符表中出现概率高的字符的编码长度尽可能小,而出现概率高的字符的编码长度相对较长.然后还要遵循前缀码的要求,就是任意一个编码都不是其他编码的前缀码,这样方便解码. 思路及实现 对于下表中的字符和相应的出现概率,有对应图中的编码树: 可以比较容易的看出来,每个叶节点就代表一个字符,从根节点到叶节点走过的路径拼接起来,就代表这个字符的编码,比如f是1100,e是1101,而f和e是深度最深的节点也是概率最小的两个节点.这也就是我们

算法导论——最短路径Dijkstra算法

package org.loda.graph; import org.loda.structure.IndexMinQ; import org.loda.structure.Stack; import org.loda.util.In; /** * * @ClassName: Dijkstra * @Description: Dijkstra最短路径算法--贪心算法 * @author minjun * @date 2015年5月27日 下午4:49:27 * */ public class D