《算法的乐趣》读书笔记


## 2018-05-16
-----------------------------
前面提到过,对于工程管理,人们最关注的两个问题分别是工程是否能顺利进行,
以及估算整个工程完成所需要的最短时间和影响工程时间的关键活动。前一个问题
可用拓扑排序解决,后一个问题则需要找出工程进行的关键路径,关键路径上的活
动完成所需要的时间就是工程完成所需要的最短时间。关键路径上的活动如果延期将直接导致工程延期。
利用AOV网表示有向图,可以对活动进行拓扑排序,根据排序结果对工程中活动的先后
顺序做出安排。但是寻找关键路径,估算工程活动的结束时间,则需要使用AOE网表示有向图。AOE网中用顶点表示事件,有向边表示活动,边上的权值表示活动持续的时间。只有在某顶点所代表的事件发生后,从该顶点出发的各有向边所代表的活动才能开始,反之亦然,只有在只想某一顶点的各有向边所代表的活动都已经结束后,该顶点所代表的事件才能发生。AOE网只有一个入度为0的顶点(源点)和一个出度为0的顶点(汇点),分别代表开始事件和结束事件,其他的顶点则表示两个意义,其一是此点以前的所有活动都已经结束,其二是此点之后的活动可以开始了。

工程管理最关注的两个问题:
1. 能否顺利进行
2. 完成需要的最短时间

AOV图:
1. 顶点 表示 事件
2. 有向边 表示 活动
3. 边上的权值 表示 活动持续的时间
4. 只有一个入度为0的源点和出度为0的汇点,表示开始时间和结束事件

 

## 2018-05-17
-----------------------------
前面提到过,对于工程管理,人们最关注的两个问题分别是工程是否能顺序进行,以及整个工程完成所需要的最短时间和影响工程时间的关键活动。前一个问题可用拓扑排序解决,后一个问题则需要找出工程进行的关键路径,关键路径上的活动完成所需要的时间就是工程完成所需要的最短时间。关键路径通常是所有工程活动中最长的路径,关键路径上的活动如果延期将直接导致工程延期。
利用AOV网表示有向图,可以对活动进拓扑排序,根据排序结果对工程中活动的先后顺序做出安排。但是寻找关键路径,估算工程活动的结束时间,则需要使用AOE网表示有向图。AOE网中用顶点表示事件,有向边表示活动,边上的权值表示活动持续的时间。只有在某顶点所代表的事件发生后,从该顶点出发的各有向边所代表的活动才能开始,反之亦然,只有在指向某一顶点的各有向边所代表的活动都已经结束后,该顶点所代表的事件才能发生。AOE网只有一个入度为0的顶点(源点)和一个出度为0的顶点(汇点),分别代表开始事件和结束事件,其他的顶点则表示两个意义,其一是此点之前的所有活动都已结束,其二是此点之后的活动可以开始了。对于表9-1所列举的活动,用AOE网表示的活动如图9-3所示,其中虚线连接的顶点表示两个事件是同质事件,也就是说这两个顶点代表相同的事件,边的权是0表示这两个顶点之间没有活动。

### 总结
-----------------------------
- 工程管理,最关注的两个问题
- 工程能否顺利进行
- 工程完成的最短事件和影响工程时间的关键活动
- AOV 用于拓扑排序
- AOE 用来寻找最短路径

 

### 2018-05-18
-----------------------------
#### 关键路径算法
-----------------------------
前面提到的,对于工程管理,人们最关注的两个问题分别是工程是否能顺利进行,以及估算整个工程完成所需要的最短时间和影响工程时间的关键活动。前一个问题可用拓扑排序解决,关键路径上的活动完成所需要的时间就是工程完成所需要的最短时间。关键路径通常是所有工程活动中最长的路径,关键路径上的活动如果延期将直接导致工程延期。

利用AOV网表示有向图,可以对活动进行拓扑排序,根据排序结果对工程中活动的先后顺序做出安排。但是寻找关键路径,估算工程活动的结束时间,则需要使用AOE网表示有向图。AOE网中用顶点表示事件,有向边表示活动,边上的权值表示活动持续的时间。只有在某顶点所代表的事件发生后,从该顶点出发的个有向边所代表的活动才能开始,反之亦然,只有在指向某一顶点的各有向边所代表的活动都已经结束后,该顶点所代表的事件才能发生。AOE网只有一个入度为0的顶点(源点)和一个出度为0的顶点(汇点),分别代表开始事件和结束事件,其他的顶点则表示两个意义,其一是此点之前的所有活动都已经结束,其二是此点之后的活动可以开始了。对于表9-1所列举的活动,用AOE网表示的结果如图9-3所示,其中虚线连接的顶点表示两个事件是同质事件,也就是说这两个顶点代表相同的事件,边的权是0表示这两个顶点之间没有活动。

计算关键路径的算法需要根据AOE网的特征调整图的数据结构定义,本节介绍的算法仍然使用邻接表离开表示图,但是需要重新定义顶点和边的数据结构。因为AOE网的边代表具体的活动,需要在数据结构中明确体现“边”的定义,调整后的边和顶点的定义如下所示:
```
typedef struct tagEdgeNode
{
int vertexIndex; //活动边终点顶点索引
std::string name; //活动边的名称
int duty; //活动边的时间(权重)
}EDGE_NODE;

typdedef struct tagVertexNode
{
int sTime; //事件最早开始时间
int eTime; //事件最晚开始时间
int inCount; //活动的前驱节点个数
std::vector<EDGE_NODE> edges; //相邻边表
}VERTEX_NODE;
```
算法开始之前,每个顶点的sTime被初始化为0,eTime被初始化为一个有效范围之外的最大值(0x7FFFFFFF),算法结束之后,sTime和eTime会被计算为实际的时间值。

 

### 2018.5.21
-----------------------------
9.3 关键路径算法
前面提到过,对于工程管理,人们最关注的两个问题分别是工程是否能顺利进行,以及估算整个工程完成所需要的最短时间和影响工程时间的关键活动。前一个问题可用拓扑排序解决,后一个问题则需要找出工程进行的关键路径,关键路径上的活动完成所需要的时间就是工程完成所需要的最短时间。关键路径通常是所有工程活动中最长的路径,关键路径上的活动如果延期将直接导致工程延期。

利用AOV网表示有向图,可以对活动进行拓扑排序,根据排序结果对工程中的先后顺序做出安排。但是寻找关键路径,估算过程活动的结束时间,则需要使用AOE网表示有向图。AOE网中用顶点表示事件,有向边表示活动,边上的权值表示活动持续的时间。只有在某顶点所代表的事件发生后,从该顶点出发的个有向边所代表的活动才能开始,反之亦然,只有在指向某一顶点的各有向边所代表的活动都已经结束后,该顶点所代表的事件才能发生。AOE网只有一个入度为0的顶点(源点)和一个出度为0的顶点(汇点),分别代表开始事件和结束事件,其他的顶点则代表两个意义,其一是此点之前的所有活动都已结束,其二实此点之后的活动可以开始了。对于表9-1所列举的活动,用AOE网表示的结果如图9-3所示,其中虚线连接的顶点表示两个事件是同质事件,也就是说这两个顶点代表相同的事件,边的权是0表示这两个顶点之间没有活动。

计算关键路径的算法需要根据AOE网的特征调整图的数据结构定义,本节介绍的算法仍然使用邻接表来表示图,但是需要重新定义顶点和边的数据结构。因为AOE网的边代表具体的活动,需要在数据结构中明确体现“边”的定义,调整后的边和顶点的定义如下所示:
```
//边
typedef struct tagEdgeNode
{
int vertexIndex; //活动边终点顶点索引
std::string name; //活动边的名称
int duty; //活动边的时间(权重)
}EGEE_NODE;

//顶点
typedef struct tagVertexNodex
{
int sTime; //事件的最早开始时间
int eTime; //事件最晚开始时间
int inCount; //活动的前驱节点个数
std::vector<EDGE_NODE> edges; //相邻边表
}VERTEX_NODE;
```
算法开始之前,每个顶点的sTime被初始化为0,eTime被初始化为一个有效范围之外的最大值(0x7FFFFFFF),算法结束之后,sTime和eTime会被计算为实际的时间值。

9.3.1 什么是关键路径
开始讨论关键路径之前,先来介绍一下活动的最早开始时间和最晚开始时间。工程中一个活动核实开始依赖于其前驱活动何时结束,只有所有的前驱活动都结束后这个互动才可以开始,前驱互动都结束的时间就是这个活动的最早开始时间。与此同时,在不影响工程完工时间的前提下,有些活动的开始时间存在一些余量,在时间余量允许的范围之内推迟一段时间开始活动也不会影响工程的最终完成时间,活动的最早开始时间加上这个时间余量就是活动的最晚开始时间。活动不能在最早开始时间之前开始,当然,也不能在最晚开始时间之后开始,否则会导致工期延误。

如果一个互动的时间余量为0,即该活动的最早开始时间和最晚开始时间相同,则这个活动就是关键活动,由这些关键活动串起来的一个工程活动路径就是关键路径。根据关键路径的定义,一个工程中的关键路径可能不止一个,我们常说的关键路径指的是工程时间最长的那条路径,也就是从源点到汇点之间最长的那条活动路径

 

### 2018-05-22
-----------------------------
9.3.2 计算关键路径的算法
根据9.3.1节的介绍,计算关键路径的基础是先找出工程中的所有关键活动,确定一个活动是否是关键活动的依据就是活动的最早开始时间和最晚开始时间,因此需要先介绍如何计算活动的最早开始时间和最晚开始时间。在AOE网中,事件ei必须在指向ei的所有活动都结束后才能发生,只有ei发生之后,从ei发出的活动才能开始,因此ei的最早发生时间就是ei发出的所有活动的最早开始时间。如果用est[i]表示事件ei的最早开始时间,用duty[i,j]表示连接事件ei和事件ej的活动需要持续的时间,则事件ei的最早开始时间可以用以下关系推算:
1. est[0] = 0
2. est[n] = max{est[i] + duty[i,n], est[j] + duty[j,n], ..., est[k] + duty[k,n]}
(其中I,j,...,k是事件n的前驱事件)
根据以上推算关系,可以将图9-3中的e0~e3几个事件的最早开始时间推算出来:
est[0] = 0
est[1] = est[0] + duty[0,1] = 0 + 8 = 8
est[2] = est[0] + duty[0,2] = 0 + 5 = 5
est[3] = max{est[1] + duty[1,3], est[2] + duty[2,3]} = max{8+0,5+0} = 8
很显然,这个推算关系是建立在合法的拓扑序列的基础上的,因此,推算事件的最早开始时间需要对图中的事件节点进行拓扑排序。拓扑排序的算法在9.2节介绍过了,现在我们只关注最早开始时间的计算进方法。假设sortedNode参数中存放的图的拓扑排序额结果,CalcESTime()函数从拓扑序列的第一个顶点开始(变量u代表的顶点),遍历这个顶点发出的有向边指向的相邻顶点(变量v代表的顶点),如果该顶点的最早开始时间与有向边代表的活动持续时间的和(这个结果存放在临时变量uvst中)大于有向边执行的的相邻顶点的最早开始时间,则更新这个相邻顶点的最早开始时间。需要注意的是,算法并没有直接利用推算关系中的max选择处理,而是按照sortedNode序列中的顶点先后关系,只在处理到相邻顶点时才更新最早开始时间(这正是所有顶点的sTime被初始化成0的原因),当sortedNode序列中的所有顶点都处理完之后,就相当于变相地实现了max选择的处理。
综合前面的分析,计算关键路径的需要以下四个步骤:
1. 对事件顶点进行拓扑排序,得到事件的拓扑序列;
2. 计算事件顶点的最早开始时间;
3. 计算事件顶点的最晚开始时间;
4. 计算活动的最早开始时间和最晚开始时间,并按照事件的拓扑顺序逐次输出关键活动,得到关键路径。

 

### 2018-05-23
-----------------------------
9.4 总结

现在回到本章章首的那个例子,一组没有任何关系的活动,在一定的规则或常识的约束下,在活动的某个属性(开始时间)上形成了或弱或强的顺序关系,这就是一个偏序,在这个偏序上排序得到的一个全序就是这组活动的拓扑排序。这种偏序关系的强弱取决于规则和约束力的大小,正常情况下穿衣服应该在坐班车之前发生,但是我也可以选择在班车上穿衣服。当然,这取决于我失去理智的程度。

生活中有许多看似神奇但是原理却很简单的东西,本章介绍的两个算法就是这样,工程管理软件中最实用的两个功能,原理就是两个简单的算法在背后支撑其实现。很多软件,无论是动辄几百兆字节的大型软件,还是几十千字节定的小程序,背后都是不同的算法在支撑其展示的各种功能,没有任何神秘可言,本章给出的例子只是这类软件功能的冰山之一角罢了。

这两个算法用到了图、数组和带优先级标记队列等数据结构,灵活地运用这个数据结构给算法实现带来了极大的便利,比如,普通的拓扑排序和本章给出的按照开始时间排序在算法结构上完全一样,唯一的区别就是使用带优先级标记的队列代替普通的队列。

 

### 2018-05-24
-----------------------------
工作分解结构 WBS Work Breakdown Structure
面对一堆关系错综复杂的活动,如何安排和组织这些活动,让它们在合适的时间开始,最终能在最短的时间内结束,往往是项目管理者最头疼的事情。

有向图的拓扑排序和关键路径查找

有向无环图Directed Acyclic Graph,DAG
DAG有向无环图是描述工程或项目进行过程的有效工具,项目分解后的具体活动之间定的关系,可以用有向无环图表示,很显然,这些活动如果存在构成环的顺序依赖关系,会造成环中的活动都无法进行。

顶点表示活动网 Activity On Vertex network AOV
边表示活动网 Activity On Edge newtwork AOE

AOV 顶点表示活动
AOE 边表示活动

 

### 2018-05-25
-----------------------------
9.2 排序
-----------------------------
在图论中,一个有向无环图的所有顶点可以排成一个线性序列,当这个线性序列满足以下条件时,称该序列为一个满足图的拓扑次序的序列。
- 图中的每个顶点在序列中只出现一次;
- 对于图中任意一个有向边(u,v),在该序列中顶点u一定位于顶点v之前。
这样的序列也被称为拓扑序列,对有向图的所有顶点排序,活动拓扑排序序列的过程就是有向图的拓扑排序。拓扑排序并不仅仅用于有向图,它是一种利用数据元素中某个属性的偏序关系得到数据元素的全排序序列的方法,本章的内容只关注基于有向图的拓扑排序方法。

 

### 2018-05-28
-----------------------------
9.2 拓扑排序

在图论中,一个有向无环图的所有顶点可以排成一个线性序列,当这个线性序列满足以下条件时,称该序列为一个满足图的拓扑次序(topological order)的序列。
- 图中每个顶点在序列中只出现一次;
- 对于图中任意一条有向边(u,v),在该序列中顶点u一定位于顶点v之前。
这样的序列也被称为拓扑序列,对于有向图的所有顶点排序,获得拓扑序列的过程就是有向图的拓扑排序(topological sorting)。拓扑排序并不仅仅用于有向图,它是一种利用数据元素中某个属性的偏序关系得到数据元素的全排序序列的方法,本章的内容只关注基于有向图的拓扑排序方法。

 

posted @ 2018-05-16 11:30  jiftle  阅读(927)  评论(0编辑  收藏  举报