目录
前言
无
一、最小生成树
1、最小生成树的概念
1、对于一个带权连通无向图 G = (V, E),生成树不同,每棵树的权(即树中所有边上的权值之和)也可能不同。设 R 为 G 的所有生成树的集合,若 T 为 R 中边的权值之和最小的生成树,则称 T 为 G 的最小生成树(Minimum-Spanning-Tree, MST)
2、最小生成树能有多个,但是边的权值之和总是唯一且最小
3、最小生成树的边数 = 定点数 - 1 。砍掉一条边则不连通,增加一条边则会出线回路
4、若一个连通图本身就是一棵树,则其最小生成树就是他本身
5、只有连通图才有生成树,非连通图只有生成森林
2、最小生成树的构建
1、Prim(普里姆)算法
普里姆算法这名字听上去是从日本那里传过来的,不然不应该叫做普瑞姆算法吗?
言归正传,Prim算法的核心思想是:
从某一个顶点开始构建生成树;每次将代价最小的新顶点纳入生成树,直到所有顶点都纳入为止。
因此需要构建两个列表,用于存储 顶点加入信息、起始顶点到该顶点的最小代价。
在使用代码实现时,总计需要遵循3个步骤:1、遍历所有结点,从未加入的顶点中选择代价最小的顶点,加入树;2、再次遍历所有顶点,更新所有未加入顶点的最小代价;3、循环前两步,直至所有顶点都加入。
2、Kruskal(克鲁斯卡尔)算法
这算法一听就知道是德国人提出的。
核心思想:每次选择一条权值最小的边,使这条边的两头连通(原本已经连通的就不选);直到所有结点都连通
在使用代码实现的过程中,需要注意两个步骤:1、首先将所有边按照权值大小,由小到大进行排序;2、在第 i 轮中,检查第 i 条边的两端顶点是否连通(是否属于同一集合),若连通,则跳过;若不连通,则使其连通。
注意:会使用到并查集的知识。
3、两种构建方式的比较
Prim算法采用的思想是遍历顶点,一共需要遍历 |v| 个顶点,每个顶点需要遍历其他顶点,因此其时间复杂度是。因此该算法更适用于边稠密图。
Kruskal算法采用的思想是遍历每一条边,一共需要遍历 |e| 条边,在判断边的两端是否属于同一集合时,时间复杂度为。因此其时间复杂度为。因此该算法更适用于边稀疏图。
3、最短路径问题
1、单源最短路径(BFS)
单源,即仅从一个顶点出发到达其余所有顶点。
采用BFS算法,可以用于处理无权图或者所有边的权值都相等的图。
代码实现方面也十分简单,仅需要在调用 vist() 函数时修改其最短路径长度 d[] 并在 path[] 记录前驱结点。
注意:广度优先生成树一定是高度最小的生成树
2、单源最短路径(Dijkstra)
这个算法很有名,可以用于处理带权图、无权图。
这个算法每一轮都有两个步骤:1、添加最短路径并固定;2、更新路径信息。直接来看例子。
注意:不能用于处理带负权值的图
此处,先添加V2,后添加V1,导致无法根据V1的数据更新最短路径。
3、各顶点间的最短路径(Floyd-Warshall )
Floyd算法的基本思想是将点到点的最短距离使用动态规划的思想,拆分成多个阶段:第 i 轮,考虑从点 中转时,点V到点W的最短距离是多少。
即每多一轮,都会考虑从新的顶点出发到其余顶点的最短距离。
代码实现方面非常简单,首先需要获取各顶点到达其余顶点的初始距离信息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;
}
}
}
}
注意:不能解决带有“负权回路”的图(回路中存在带有负权值的边),这种图可能没有最短路径
其时间复杂度是,空间复杂度是
二、有向无环图(DAG)
若一个有向图中不存在环,则称为有向无环图,简称 DAG 图(Directed Acyclic Graph)
例如上图,左图是DAG,右图不是。
对于下图表达式,若是采用树的形式来表达,则是没有效率的,因为圈出部分是重复使用过的,因此可以合并到一起。
如图,每一个顶点都没有重复的操作数。
操作步骤:1、把各个操作数不重复地排成一排;2、标出各个运算符的生效顺序(先后顺序有点出入无所谓);3、按顺序加入运算符,注意“分层”;4、从底向上逐层检查同层的运算符是否可以合体
三、拓扑排序
1、AOV网
AOV 网(Activity On Vertex Network,用顶点表示活动的网):用 DAG 图表示一个工程。顶点表示活动,有向边<V1, V2>表示活动 V1 必须先于活动 V2 进行
如下图所示,就是一个AOV网
2、拓扑排序的定义
拓扑排序是对DAG图的顶点的一种排序,它使得若存在一条从顶点 A 到顶点 B 的路径,则在排序中顶点 B 一定出现在顶点 A 的后面(反过来并不成立)。每个 AOV 网都有一个或多个拓扑排序序列。
从理解的角度上来说,拓扑排序就是找到做事的顺序。例如上图AOV网中有一个拓扑排序是这样子的:
从图中可以看出,事情是一步步往下走的,切番茄的动作不可能放在洗番茄之前;AOV中也不会有从打鸡蛋到切番茄的路径。
代码实现有点麻烦,以后再说。记住,采用邻接表法时,时间复杂度是;采用邻接矩阵法时,时间复杂度是
3、逆拓扑排序
就是拓扑排序的逆推,如上图,就是。
四、关键路径
1、AOE网
AOV是指用顶点来表示活动,AOE就是用边来表示活动。
在带权有向图中,以顶点表示事件,以有向边表示活动,以边上的权值表示完成该活动的开销(如完成活动所需的时间),称之为用边表示活动的网络,简称 AOE 网(Activity On Edge Network)
性质:1、只有在某顶点所代表的事件发生后,从该顶点出发的 各有向边所代表的活动 才能开始;2、只有在进入某顶点的 各有向边所代表的活动 都已结束时,该顶点所代表的事件才能发生。另外,有些活动是可以并行进行的
AOE 网中仅有一个入度为 0 的顶点(事件开启无前置),称为开始顶点(源点),它表示整个工程的开始;也仅有一个出度为 0 的顶点(事件结束无后续),称为结束顶点(汇点),它表示整个工程的结束。
从源点到汇点的有向路径可能有多条,所有路径中,具有最大路径长的的路径称为关键路径,而把关键路径上的活动称为关键活动
2、关键路径的求解
写到这里,我看着笔记,头有点大,
求解关键路径首先要明确两个概念,一个是事件,一个是活动。在AOE图中,活动是边,顶点是事件。
其次是每个事件和活动都有两个属性,分别为最早发生时间与最迟发生时间:事件的记为 与 ;活动的记为 与 。
下面是详细步骤:
1、第一步,按照拓扑排序,计算事件最早发生时间
2、第二步,按照逆拓扑排序,计算事件最迟发生时间
3、第三步,每一个活动都可表示为,因此,其最早发生时间
4、第四步,每一个活动都可表示为,因此,其最迟发生时间
5、求剩余活动时间余量
其中 d 的值为 0 的活动就是关键活动,所组成的路径就是关键路径。
3、关键路径的特性
1、若关键活动耗时增加,则整个工程的工期将增长
2、缩短关键活动的时间,可以缩短整个工程的工期
3、当缩短到一定程度时,关键活动可能变成非关键活动
注:可能有多条关键路径,只提高一条关键路径上的关键活动速度并不能缩短整个工程的工期,只有加快那些包括在所有关键路径上的活动才能达到缩短工期的目的
后记
明日开始查找的复习