数据结构9-拓扑排序和关键路径
拓扑排序和关键路径
拓扑排序
一个任务通常可以被分解成若干个子任务,某些情况下,子任务要求有序
基本概念
AOV网
- 在有向图中,顶点表示活动,有向边表示活动间的先后关系,称这样的有向图为AOV网
- 在AOV网中,如果活动Vi必须在活动Vj之前进行,则存在有向边Vi->Vj
- AOV网中不能出现有向回路,即有向环,否则意味着某项活动以自己为先决条件
拓扑序列:把AOV网中的所有顶点排成一个线性序列,在拓扑序列中,先进性的任务一定在后进行的任务前面,按照拓扑序列完成各子任务,就可以顺利完成整个任务
拓扑排序:构造AOV网的拓扑序列的过程
拓扑排序算法的基本步骤
- 从图中选择一个入度为0的顶点并输出
- 从图中删除该顶点及该顶点引出的所有边
- 执行①②,直至所有顶点已输出,或图中剩余顶点入度均不为0(说明存在环)
对于任何无环的AOV网,其顶点均可排成拓扑序列,其拓扑序列未必唯一
拓扑排序的实现
准备工作(假定AOV网以邻接表的形式存储)
- 数组InDegree[]:InDegree[i]作为顶点i的入度
- 建立一个栈存放入度为0的顶点,每当一个顶点呃入度为0,就将其压栈,每次找入度为0的顶点时,就弹栈
求每个顶点的入度
1 | void getIndegree(Vertex Head[],int n,int InDegree[]) |
1 | void getInDree(Vertex Head[],int n,int InDegree[]) |
拓扑排序
1 | bool TopoOrder(Vertex Head[],int n) |
判断拓扑序列
关键路径
AOV网:顶点表示活动或任务,有向边表示活动(或任务)间的相互关系
AOE网:有向边表示活动或任务,用边上的权值表示活动的持续时间,顶点称为事件,表示其入边的任务已完成,出边的任务可开始的状态
关键路径:完成整个工程所需的最短时间取决于从源点到汇点的最长路径长度,这条路径最长的路径就叫做关键路径
关键活动:关键路径上的活动
与关键活动有关的量
事件Vj的最早发生时间:ve(j) 最晚发生时间vl(j)
活动ai的最早发生时间:e(i) 最晚发生时间l(i)
- 事件Vj的最早发生时间ve(j)
- 事件Vj的最迟发生时间vl(j)
- 活动ai的最早开始时间e(i)
- 活动ai的最迟开始时间l(i)
关键路径和关键活动
关键路径:从源点到汇点的最长路径
关键活动:关键路径上的或从,活动的最早开始时间等于活动的最迟开始时间,即l(i)=e(i)
计算ve
计算顶点的最早发生时间,存入ve数组(假定图中顶点已按拓扑序编号)
1 | void VertexEarliestTime(Vertex Head[],int n,int ve[]) |
图中顶点未按拓扑序编号
- 方案一:先执行拓扑排序,将拓扑序存在数组Topo
1
2
3
4
5
6
7
8
9
10
11
12
13
14void VertexEarliestTime(Vertex Head[],int Topo[],int n,int ve[])
{
//拓扑序存储在Topo数组中
for(int i=1;i<=n;i++)
ve[i]=0;
for(int i=1;i<=n;i++)
for(Edge* p=Head[Topo[i]].adjacent;p!=NULL;p=p->link)
{
int k=p->veradj;
if(ve[Topo[i]]+p->cost>ve[k])
ve[k]=ve[Topo[i]]+p->cost;
}
} - 拓扑排序过程中顺带更新ve,无需调用上述函数
原理
拓扑排序:按拓扑序选出一个点,扫描其邻接顶点k,更新顶点k的入度
求ve值:按拓扑序选出一个点,扫描其邻接顶点k,更新顶点k的ve值1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23void TopoOrder(Vertex Head[],int n)
{
int InDegree[N];
Stack s;
InDegree(Head,n,InDegree);//求每个点的入度
for(int i=1;i<=n;i++)
if(InDegree[i]==0)
s.push(i);
for(int i=1;i<=n;i++)
{
if(s.empty()) return;//有环
int j=s.pop();//选出入度为0的点
for(Edge* p=Head[j].adjacent;p!=NULL;p=p->link)
{
int k=p->veradj;
InDegree[k]--;
if(InDegree[k]==0) s.push(k);
}
if(ve[j]+p->cost>ve[k]) ve[k]=ve[j]+p->cost;
}
}
计算vl
1 | void VertexLatestTime(Vertex Head[],int n,int ve[],int vl[]) |
1 | void VertexLatestTime(Vertex Head[],int n,int Topo[],int ve[],int vl[]) |
计算活动的最早和最迟开始时间
1 | void ActivityStartTime(Vertex Head[],itn n,int ve[],int vl[]) |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Bin's blog!