有向无环图及其应用
一.有向无环图的概念
一个无环的有向图称作有向无环图。简称DAG图。DAG图是相较于有向树的更特殊的图。比如:
检查一个图是否有环,可以通过遍历+标记的方式进行检查,若某个顶点的弧指向了另一个已经遍历过的顶点,则该图必定含有环。
二.拓扑排序(AOV网)
1.概念
来自百度:
对一个 有向无环图 (Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个 偏序 得到该集合上的一个 全序 ,这个操作称之为拓扑排序。
2.偏序与全序
定义可以自己百度,这里记一下我对于这个偏序与全序的理解。
a).偏序

偏序里的集合的成员,只能部分的访问到,存在某个顶点,无法通过其指向访问的顶点,比如这个图,V2 无法访问到 V3, V3无法访问到V2 。V1可以通过指向V2指向V4访问到V4。
b).全序

全序是指,所有的成员都可以互相比较。
比如这个图,图中任意两个顶点,都是可以从图中找到一条以上的通路而访问到。
c).偏序与全序的区别
用具体例子来说,偏序可以表示为某些科目依赖关系,而全序可以理解为设计出来的学习计划。
举个例子:偏序表告诉我们学习控制理论需要先学习高数1、2和信号与系统,信号与系统需要先学习高数1,2。
那么全序就是我们的学习计划:先学习高数1,再学习高数2,再学习信号与系统,再学习控制理论。
3.拓扑有序
如果我们通过自己添加弧来使得一个偏序变成全序,那么这个操作就是拓扑排序而这个全序被称作拓扑有序。
某个偏序的拓扑有序是不唯一的:排序的方式不同,所以人为添加的弧的方式也不同,所以一个偏序的拓扑有序是不唯一的,它会有多个。
4.拓扑排序的过程
- 再有向图中,选择一个没有前驱的顶点且输出。
- 从图中删除该顶点和它为尾的弧。
- 重复1、2直到所有的顶点都已输出,或当前图中不存在无前驱的顶点为止(有环)。
三.关键路径(AOE网)
1.概念
AOE 网是在 AOV 网的基础上,其中每一个边都具有各自的权值,是一个有向无环网。其中权值表示活动持续的时间。
所以我们AOE网的建立至少要满足拓扑有序。
使用 AOE 网可以帮助解决这样的问题:如果将 AOE 网看做整个项目,那么完成整个项目至少需要多少时间?
解决这个问题的关键在于从 AOE 网中找到一条从起始点到结束点长度最长的路径,这样就能保证所有的活动在结束之前都能完成。
起始点是入度为 0 的点,称为“源点”;结束点是出度为 0 的点,称为“汇点”。这条最长的路径,被称为”关键路径“。
为了求出一个给定 AOE 网的关键路径,需要知道以下 4 个统计数据:
- 对于 AOE 网中的顶点有两个时间:最早发生时间(用 Ve(j) 表示)和最晚发生时间(用 Vl(j) 表示);
- 对于边来说,也有两个时间:最早开始时间(用 e(i) 表示)和最晚开始时间( l(i) 表示)。
2.实现
对照这个图来讲:

a).最早发生时间Ve(j)
这里的最早发生时间,实际上是事件最早能多久开始,也就是前面的时间路线的最长的那一条,就比如你要沏茶肯定得水先烧好,就算把茶叶放进去了你还是得等水。
Ve(j):对于 AOE 网中的任意一个顶点来说,从源点到该点的最长路径代表着该顶点的最早发生时间,通常用 Ve(j) 表示。
例如,图 1 中从 V1 到 V5 有两条路径,V1 作为源点开始后,a1 和 a2 同时开始活动,但由于 a1 和 a2 活动的时间长度不同,最终 V1-V3-V5 的这条路径率先完成。但是并不是说 V5 之后的活动就可以开始,而是需要等待 V1-V2-V5 这条路径也完成之后才能开始。所以对于 V5 来讲,Ve(5) = 7。

b).最晚发生时间Vl(j)
还是用泡茶的例子,因为烧水需要一定的时间,所以放茶叶并不需要在刚烧水就开始,也可以在水开之前开始,后者就是我们的最晚发生时间。
Vl(j):表示在不推迟整个工期的前提下,事件 Vk 允许的最晚发生时间。
例如,在得知整个工期完成的时间是 18 天的前提下,V7 最晚要在第 16 天的时候开始,因为 a10 活动至少需要 2 天时间才能完成,如果在 V7 事件在推迟,就会拖延整个工期。所以,对于 V7 来说,它的 Vl(7)=16。

c).e(i)
表示活动 ai 的最早开始时间,如果活动 ai 是由弧 <Vk,Vj> 表示的,那么活动 ai 的最早开始的时间就等于时间 Vk 的最早发生时间,也就是说:e[i] = ve[k]。

d).l(i)
l(i):表示活动 ai 的最晚开始时间,如果活动 ai 是由弧 <Vk,Vj> 表示,ai 的最晚开始时间的设定要保证 Vj 的最晚发生时间不拖后。所以,l[i]=Vl[j]-len<Vk,Vj>。

四.代码
1.AOV

样例输入与输出:
please input the number of Vertex and Arc:6 8
please input Vertexs' name:
123456
please input (tail,head) as the arc:
0 1
0 2
0 3
2 1
2 4
3 4
5 3
5 4
No.0 inArc:0 Vex:1 to 2 3 4
No.1 inArc:2 Vex:2 to
No.2 inArc:1 Vex:3 to 2 5
No.3 inArc:2 Vex:4 to 5
No.4 inArc:3 Vex:5 to
No.5 inArc:0 Vex:6 to 4 5
One AOV is: 6 1 4 3 5 2
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define OK 1
#define ERROR 0
#define MaxLen 100
typedef struct ArcNode{
int Head;
struct ArcNode *nextArc;
}ArcNode; // 创建弧结点
typedef struct VNode{
char NodeName;
int inNum;
ArcNode *nextArc;
}VNode; // 创建Vertex顶点结点
typedef struct Graph{
int len;
VNode *Nbase; // 线性存储顶点结点
}Graph; // 创建一张图
int MarkGraph[MaxLen]; // 标记数组
Graph *GraphCreat(void);
int GraphShowList(Graph *G);
int GraphShowAOV(Graph *G);
int main()
{
Graph *map = GraphCreat();
GraphShowList(map);
GraphShowAOV(map);
return 0;
}
Graph *GraphCreat(void)
{
Graph *G = (Graph*)malloc(sizeof(Graph));
int lenV, lenA;
int i, tail, head;
char chname[MaxLen];
char temp;
ArcNode *ArcNow, *ArcLast;
printf("please input the number of Vertex and Arc:");
scanf("%d %d", &lenV, &lenA); // 获取 顶点数和弧的个数
if (lenV > MaxLen)
{
printf("Over MaxLenth");
exit(ERROR);
} // 限制下大小
// 创建顶点线性表
G->len = lenV;
G->Nbase = (VNode*)malloc(sizeof(VNode)*lenV);

本文介绍了有向无环图(DAG)的概念及其在拓扑排序和关键路径分析中的应用。详细阐述了拓扑排序的过程与偏序、全序的区别,并通过实例说明了如何在AOE网中找到关键路径。

1万+

被折叠的 条评论
为什么被折叠?



