系列文章目录
前言
本站内其实有许多讲如何找关键路径的,但是我看了下几篇博客,感觉都写得好难好难,有点难以理解,比如下面是某篇博客所描述的确定关键路径的算法:
看完后是一脸懵逼的状态。那么是否有我们工程人方便理解的算法呢,那必然是有的,详见下文。
一、算法的确定
根据我们考建造师的学习内容,大家都知道:可以依靠总时差来确定关键路径。即关键路径上的活动的总时差是为0的。因此我们的算法就可以简单的归纳为以下四步:
1、求该项目中所有活动的最早开始时间
2、求该项目中所有活动的最晚开始时间
3、求该项目中所有活动的总时差
4、依次遍历该项目中所有活动的总时差(或最早开始时间是否等于最晚开始时间),如果总时差等于0,那么就把当前活动添加到关键路径列表中。
二、模型的建立
首先我们确定一个研究模型,方便我们检验算法是否满足要求。这里我选择RCPLIB数据集下文件名为“mv1.rcp”的文件中的数据做参考,为了方便我们直观地理解模型,我将这个文件中的数据整理成如下字典的形式。
{ 1:{"successors":[2, 3, 4, 5],"predecessors":[],"duration":0}, 2:{"successors":[6],"predecessors":[1],"duration":2}, 3:{"successors":[10],"predecessors":[1],"duration":4}, 4:{"successors":[9],"predecessors":[1],"duration":6}, 5:{"successors":[11],"predecessors":[1],"duration":9}, 6:{"successors":[7],"predecessors":[2],"duration":8}, 7:{"successors":[8, 11],"predecessors":[6],"duration":10}, 8:{"successors":[12],"predecessors":[7],"duration":4}, 9:{"successors":[12],"predecessors":[4],"duration":3}, 10:{"successors":[12],"predecessors":[3],"duration":5}, 11:{"successors":[12],"predecessors":[5, 7],"duration":1}, 12:{"successors":[],"predecessors":[8, 9, 10, 11],"duration":0} }
其中,“2:{"successors":[6],"predecessors":[1],"duration":2}”代表该项目中活动序号为2的活动的紧后活动为活动6,活动序号为2的活动的紧前活动为活动1,活动序号为2的活动的工期为2。以此类推。
这里我简单地手画一个AoN图方便我们理解:
请大家谅解,实在懒得找画图工具画了哈哈哈哈哈
三、代码的实现
算法很清晰,故而咱们代码也很清晰,就三个函数:calculate_early_start_time(),calculate_late_start_time(),find_critical_path()。顾名思义,即找最早开始时间的函数,找最晚开始时间的函数,和找寻关键路径的函数。代码如下:
def calculate_early_start_time(project):
"""
计算各个活动的最早开始时间(Early Start Time),返回一个字典。
"""
early_start_time = {1: 0}
for i in range(2, len(project)+1):
predecessors = project[i]["predecessors"]
max_time = max([early_start_time[p] + project[p]["duration"] for p in predecessors])
early_start_time[i] = max_time
return early_start_time
def calculate_late_start_time(project, early_start_time):
"""
计算各个活动的最晚开始时间(Late Start Time),返回一个字典。
"""
late_start_time = {}
max_time = max(early_start_time.values())
late_start_time[12] = max_time
for i in range(len(project)-1, 0, -1):
successors = project[i]["successors"]
min_time = min([late_start_time[s] - project[i]["duration"] for s in successors])
late_start_time[i] = min_time
return late_start_time
def find_critical_path(project):
"""
找到项目的关键路径,返回关键路径上的活动序号列表。
"""
early_start_time = calculate_early_start_time(project)
late_start_time = calculate_late_start_time(project, early_start_time)
critical_path = []
for i in range(1, len(project)+1):
if early_start_time[i] == late_start_time[i]:
critical_path.append(i)
return critical_path
# 项目为
project = {
1:{"successors":[2, 3, 4, 5],"predecessors":[],"duration":0},
2:{"successors":[6],"predecessors":[1],"duration":2},
3:{"successors":[10],"predecessors":[1],"duration":4},
4:{"successors":[9],"predecessors":[1],"duration":6},
5:{"successors":[11],"predecessors":[1],"duration":9},
6:{"successors":[7],"predecessors":[2],"duration":8},
7:{"successors":[8, 11],"predecessors":[6],"duration":10},
8:{"successors":[12],"predecessors":[7],"duration":4},
9:{"successors":[12],"predecessors":[4],"duration":3},
10:{"successors":[12],"predecessors":[3],"duration":5},
11:{"successors":[12],"predecessors":[5, 7],"duration":1},
12:{"successors":[],"predecessors":[8, 9, 10, 11],"duration":0}
}
critical_path = find_critical_path(project)
print(critical_path) # 输出 [1, 2, 6, 7, 8, 12]
总结
就是一个对项目管理内容的基本的代码的实现。此外,我们也可以根据关键路径上的活动的工期和算出这个项目的最短工期。