Upload
garth
View
43
Download
8
Embed Size (px)
DESCRIPTION
计算机科学与技术(本科)专业. 数据结构. 第十一讲 图的应用. 目 录. ● 最小生成树. ● 活动网络. ● 单源最短路径简介. §8.4 最小生成树 (Minimum-cost Spanning Tree). 一、 MST 概述. 1 、 ST—— 对于有 n 个顶点的连通图,包括所有的顶点和仅能将这些顶点连通在一起的最少条边( n – 1 )的子图(又名极小连通子图),即为该连通图的生成树( ST ). - PowerPoint PPT Presentation
Citation preview
计算机科学与技术(本科)专业
● 最小生成树
● 活动网络
● 单源最短路径简介
§8.4 最小生成树(Minimum-cost Spanning Tree)
一、 MST 概述 1 、 ST—— 对于有 n 个顶点的连通图,包括所有的顶点和仅能将这些顶点连通在一起的最少条边( n – 1 )的子图(又名极小连通子图),即为该连通图的生成树( ST ) 2 、 ST 的多样性——对图遍历时访问的结点和经由的边就构成了生成树,因遍历的路径和选择的起始点的不同,所经由边也不同,所以一个连通图的 ST 有多个方案3 、 MST
连通图的边带有权值,则连通图又称为网络在网络中边上权值之和最小的生成树叫 MSTMST 是一个具有应用价值的问题在已知网络中求 MST 的方法有 Kruscal 和 Prim 两种最常用
二、克鲁斯卡尔算法1 、思路描述
最初构造只有 n 个顶点没有边的 n 个连通分量的集合每次选出权值最小且两端点在不同连通分量上的边将这个边加入到集合中,使图的连通分量数减 1重复以上两步,直到集合中只有一个连通分量为止
0 1
2 3
10 16
1225
4
5 622
1824
28
14
(a) 带权连通图
10
25
16
12
22
140 1
2 3 4
5 6
(b)Kruscal 求解 MST 过程图
2 、存贮结构图采用邻接矩阵
0 1 2 30
1
2
3
4 5 6
4
5
6
利用最小堆 MinHeap 存放所有边,堆(边)结点格式:
tail (边的顶点位置)
head (边的顶点位置)
cost (边的权值)
借助并查集 UFSets 实现运算
3 、最小生成树类声明
const float Maxnum= 机器可表示的极大数;class MinSpanTree;class MSTEdgeNode { //MST 边结点声明 friend class MinSpanTree;private: int tail, head; float cost;public: MSTEdgeNode( ): tail(-1), head(-1), cost(0){ } };class MinSpanTree: public Graph<Type> { //MST 类定义protected: MSTEdgeNode * edgevalue; // 用边值数组表示树 int MaxSize, n; // 数组元素的最大个数和当前个数public: MinSpanTree(int sz = NumofVertices( ) - 1): MaxSize(sz), n(0) {edgevalue = new MSTEdgeNode [MaxSize];} int Insert (MSTEdgeNode & item); void Kruscal (MinSpanTree & T ); }
4 、求解最小生成树的实现
void MinSpanTree :: Kruscal (MinSpanTree &T ){ MSTEdgeNode e; MinHeap<MSTEdgeNode> H (currentEdges); // 用最小堆存边 int NumVertices = VerticesList.last+1, u, v; UFSetes F(NumVertices); // 用并查集表示连通分量 for (u = 0; u < NumVertices; u + +) // 建立最小堆的数据
for (v = 0; v < NumVertices; v + +) if (Edge[u][v]!=Maxnum && Edge[u][v]!=0) {e.tail=u; e.head=v; e.cost=Edge[u][v]; H.Insert(e);}
int count=0; // 生成树边的计数 while(count < NumVertices) { // 反复执行,取 n-1 条边
H.RemoveMin(e); // 从最小堆中退出具有最小值的边u=F.Find(e.tail); v=F.Find(e.head); if(u != v){ // 两顶点所在集合的根不是同一集合,属不连
通F.Union(u,v); T.Insert(e); count + +;} } }
三、普里姆算法1 、思路描述
从某顶点 u0 出发,选择与之关联并具有最小权值的边( u0 , v ),将顶点 v 加入到 U 中 以后每次从一个顶点在 U 中,另一个不在 U 中且具有最小权值的边( u , v ),将顶点 V 加入到 U 中,直到所有顶点都加入到 U 为止。
0 1
2 3
10 16
1225
4
5 622
1824
28
14
(a) 带权连通图
0 1
2 3 4
5 6
(b) Prim 求解 MST 过程图U={0 , }
10
2 ,
25
5 ,
22
6 ,
12
4 ,
16
1 ,
14
3
lowcost[ ] 存放 U 中各顶点到 U 之外各顶点边上当前的最小权值 nearvex[ ] 记录 U 之外各顶点到 U 之内哪个顶点权值最小 举例
0 1
2 3
10 16
1225
4
5 622
1824
28
14
10280
lowcost 0 1 2 3 4 5 6
U={0}
2510280U={0,2}
22252410280U={0,2,5}
2225121810280U={0,2,5,6}
000000-1
nearvex 0 1 2 3 4 5 6
选 V=2
0200-10-1选 V=5
5-105-10-1选 V=6
-1-166-10-1选 V=4
0 1
2 3
10 16
1225
4
5 622
1824
28
14
§8.5 活动网络 (Activity Network)
一、用顶点表示活动的网络1 、顶点表示活动( activity on vertices AOV )
AOV 是用以表示一个工程的有向图图中的顶点表示一项子工程,即活动弧表示两活动之间的先后次序以计算机专业课程学习工程为例
C0
C1
C2
C3C4
C5
C0 —— 数据结构C1 —— 操作系统C2 —— 组成原理C3 —— 数据库系统C4 —— 面向对象程序设计C5 —— 计算机网络
2 、拓扑排序( topological sorting )
对于 AOV ,将所有顶点排成一个线性有序序列,使所有存在的前驱和后继关系都得到满足,该操作叫拓扑排序
C6 C7
C8
C0
C1
C2
C3C4
C5
对上例 AOV ,拓扑排序就可得到一个课程进度表: C4 , C0 , C3 , C2 , C1 , C5 或
C2 , C4 , C0 , C3 , C1 , C5 等 一般拓扑排序方案并非唯一 具有有向环的有向图无法进行拓扑排序,例如
3 、拓扑排序的方法 在 AOV 中选一个没有前驱的结点,并输出之 在图中删除该顶点和以它为尾的所有弧 重复以上两步,或输出所有顶点,组成拓扑序列;或输出部分顶点,其它顶点必构成有向环 举例
C0
C1
C2
C3
C4
C5
3 、拓扑排序的方法 在 AOV 中选一个没有前驱的结点,并输出之 在图中删除该顶点和以它为尾的所有弧 重复以上两步,或输出所有顶点,组成拓扑序列;或输出部分顶点,其它顶点必构成有向环 举例
C4 输出的拓扑序列:
C4 , C0 , C3 , C2 , C1 , C5
所有顶点输出,无有向环
C0
C2
C3C1
C5
4 、存贮表示和辅助数组 AOV 网采用邻接表存贮 设置辅助数组 count 记录各顶点的入度 以计算机专业课程学习工程 AOV 为例
C0
C1
C2
C3
C4
C5
∧C5
C4
∧C3
C2
C1
C0
3
0
1
0
3
1 1 ∧3
5
1 ∧5
0 1 ∧5
dest link
count data adj
0
1
2
3
4
5
删除以某顶点为尾的弧是用对应邻接点入度减 1 来实现
利用 count 数组中入度为 0 的分量空间构造一个存放入度为 0 的顶点的链式栈,拓扑排序中其栈顶指针 top变化情况:
C0
C1
C2
C3
C4
C5
利用 count 数组中入度为 0 的分量空间构造一个存放入度为 0 的顶点的链式栈,拓扑排序中其栈顶指针 top变化情况:
2
1
-1
2
20
1
2
3
4
5
顶点 4 出栈
2
2
-1
10
1
2
3
4
5
顶点 0 出栈
2
-1
10
1
2
3
4
5
顶点 3 出栈
C4 C0
C2
C3C1
C5
3
2
1
-1
3
10
1
2
3
4
5
-1
建链栈
top1
-10
1
2
3
4
5
顶点 2 出栈
-1
-1
0
1
2
3
4
5
顶点 1 出栈
-1
顶点 5 出栈
0
1
2
3
4
5
-1
5 、拓扑排序的算法void Graph :: TopologicalSort( ){ // 对有 n 个顶点的 AOV 拓扑排序 int top= -1; // 置栈空 for (int i = 0; i < n; i + +) // 建入度为 0 顶点的链栈 if (count[i] = = 0){count[i] = top; top = i;} // 进栈运算 for (i = 0; i < n; i + +) if (top = = -1){cout <<"Network has a cycle"<<endl; return;} else { int j = top; top = count[top]; // 入度为 0 的顶点出栈 cout<<j<<endl; Edge<float> * p = NodeTable[j].adj; while (p != NULL){ // 删掉以 j 为尾的弧 int k = p -> dest; if(- - count[k] = = 0){count[k] = top; top = k;} // 入度为 0 则进栈 p = p -> link; } } }
☆时间复杂度为 O(n + e)
二、用边表示活动的网络1 、边表示活动( activity on edges AOE )
有向边表示一个工程中的各项活动,边上的权值表示活动持续的时间( duration ) 顶点表示事件( event ),事件的发生说明在它之前的活动已完成,而在它之后的活动可以开始 AOE 举例(包括 11 个活动和 9 个事件)
0
1
2
3
4
5
6
7
8
a1=6
a2=4
a3=5
a4=1
a5=1
a6=2
a7=9
a8=7
a9=4
a10=2
a11=4
源点 汇点 图一
AOE 的意义在于估算整个工程完成的最少时间以及如何缩短工期
2 、关键路径和关键活动
0
1
2
3
4
5
6
7
8
a1=6
a2=4
a3=5
a4=1
a5=1
a6=2
a7=9
a8=7
a9=4
a10=2
a11=4
源点 汇点 图一
从源点到汇点可能有多条有向路径,路径上各活动所需时间之和叫该路径的路径长度 具有最大路径长度的路径叫做关键路径,图一的关键路径有 a1, a4, a7, a10 和 a1, a4, a8, a11, 它们的路径长度均为 18
关键路径上的所有活动都叫做关键活动,对图一的 AO
E ,关键活动是 a1, a4, a7, a8, a10 , a11
关键活动上持续时间的变化可能影响整个工程的工期
3 、事件和活动的若干量
0
1
2
3
4
5
6
7
8
a1=6
a2=4
a3=5
a4=1
a5=1
a6=2
a7=9
a8=7
a9=4
a10=2
a11=4
源点 汇点 图一
事件 Vi 的最早可以开始时间 Ve[i] :是从源点 V0 到顶点 Vi 的最长路径长度。如 Ve[4] = 6 + 1 = 7 Ve[5]=5+2=7
事件 Vi 的最迟允许开始时间 Vl[i] :是工程按期完成情况下 Vi 的最迟允许开始时间。如 Vl[4] = 18 – (4 + 7) = 7 , Vl[5] = 18 – (4 + 4) = 10 。在关键路径上有 Ve[i]=Vl[i] 活动 ak 的最早可以开始时间 e[k] :设 ak 是在 < Vi, Vj>
上, e[k] 是从源点到 Vi 的最长路径长度,故 e[k] = Ve[i] ,例如, e[4] = Ve[1] = 6 , e[6] = Ve[3] = 5
3 、事件和活动的若干量
0
1
2
3
4
5
6
7
8
a1=6
a2=4
a3=5
a4=1
a5=1
a6=2
a7=9
a8=7
a9=4
a10=2
a11=4
源点 汇点 图一
活动 ak 的最迟允许开始时间 l[k] :是工程按期完成情况下 ak
的最迟允许开始时间,设 ak 在 < Vi, Vj> 上,并 ak 的持续时间为dur(<i, j>) , l[k] = Vl[j] - dur (<i, j>) 。例如, l[4] = Vl[4] - dur (<1, 4>) = 7 – 1 = 6 l[6] = Vl[5] - dur (<3, 5>) = 10 – 2 = 8 活动 ak 的时间余量:是 l[k] – e[k] ,例如 a6 的时间余量 l[6] – e[6] = 8 – 5 = 3
a4 的时间余量 l[4] – e[4] = 6 – 6 = 0 ,对关键活动有 l[k] = e
[k]
4 、求关键路径的方法
从 V0开始,求解 AOE 顶点的拓扑排序序列
按拓扑序列次序,从 V0开始求各事件的 Ve[i]
按逆拓扑序列次序,从 Vn-1开始求各事件的 Vl[i]
根据 Ve[i] 和 Vl[i] ,求各活动的 e[k] 和 l[k]
e[k] = l[k] 的活动为关键活动,输出关键活动
1
10
50
100
30
10
20
60
0
2 3
4
带权有向图
S 集合 顶点 1 顶点 2 顶点 3 顶点 4
0 10 ( v0 ,v1) ---- 30 100
0,1 60 30(v0 ,v3) 100
0,1,3 50(v0 ,v3,v2) 90
0,1,3,2 60(v0,v3,v2,v4)
二、 Dijkstra 逐步求解的过程举例
一、 Dijkstra 求解最短路径的方法: 开始 S={0} , 求出长度最短的一条最短路径 <0,i>,S={0,i} ,然后在经由 i的情况下求长度次短的一条路径。依此类推,直到求出到所有顶点的最短路径。
§8.6 单源最短路径问题简介