关键路径

原理:

例图

 

如上图,是一个AOE网,点表示状态,边表示活动及其所需要的时间。为了求出关键路径,我们使用一下算法:

1.求出到达各个状态的最早时间(按最大计)


这个过程是要从源点开始向汇点顺推:

  1. V1是源点,其最早开始时间是0。
  2. V2、V3、V4最早时间分别是是6、4、5。
  3. 对于V5而言,V2到V5所花费时间是6+1=7,而V3到V5所花费时间是4+1=5。我们要按最大计,也就是V5最早时间是max{7,5}=7,按最大计是因为只有活动a4和a5同时完成了,才能到达V5状态。V3到V5需要5分钟,但是此时a4活动尚未完成(7分钟),所以都不能算到达V5,故而要按最大计。
  4. V6只有从V4到达,所以V6的最早完成时间是(5+2=)7。
  5. 同理,V7最早完成时间是16。
  6. 对于V8而言,和V5处理方法一致。V8=max{V5+7,V6+4}={7+7,7+4}=14。
  7. V9可算出是18。

这样,我们可以得到各个状态的最早时间的表:

最早时间表

2.求出到达各个状态的最晚时间(按最小计)


这个过程是要从汇点开始向源点逆推:

  1. V9完成时间为18,最V7最迟开始时间是(18-2=)16

    逆推


    因为活动a10所需时间2。如果V7开始时间比16晚,则V9完成时间就会比18晚,这显然不对。
  2. 同理,V8最迟开始时间为14。
  3. 对于V5而言,可以从V7、V8两个点开始向前推算,此时要按最小计,即V5(最晚)=min{V7-9,V8-7}=min{16-9,14-7}=7。
    请注意!!,min{V7-9,V8-7}中,V7、V8取的都是前面算出的最迟开始时间(而不是最早开始时间)。

    按最小计


    最小计,是因为如果按最大计去计算V5的最晚开始时间,那么加上a7和a8的活动时间后,V7、V8至少有一个会比之前逆推算得出的最晚时间还要晚,这就发生了错误。
  4. 同理,可计算出剩下的点

这样,我们可以得到各个状态的最晚时间的表:

最晚时间表

 

事实上,源点和汇点的最晚时间和最早时间必定是相同的。

3.求出关键路径


求出关键活动,则关键活动所在路径即为关键路径

对于a1:

 

这表明,a1最早只能从0时刻开始,最晚也只能从(6-6=)0时刻开始,因此,a1是关键活动。

对于a2:

 


a2最早要从0时刻开始,但是它最晚开始时间却是(6-4=)2。也就是说,从0开始做,4时刻即完成;从2开始做,6时刻恰好完成。从而在[0,2]区间内任意时间开始做a2都能保证按时完成。(请区别顶点的最早最晚和活动的最早最晚时间。图示中的最早最晚是顶点状态的时间,活动的最早最晚开始时间却是基于此来计算的)。
由于a2的开始时间是不定的,所以它不能主导工程的进度,从而它不是关键活动。

 

一般的,

 


活动用时X时间,它最早要从E1时刻开始(一开始就开始),最晚要从L2-X时刻开始(即恰好完成)。所以,如果它是关键活动,则必然有E1=L2-X,否则它就不是关键活动。

 

值得注意的是,顶点的最早开始时间等于最晚开始时间 是 该顶点处于关键路径 的 不充分不必要条件。

 


上表中蓝色底纹表示的点即为处于关键路径的点。尽管它们的最早时间与最晚时间都相同,但是这与它们是否为关键路径的点无关。因为这还取决于起始点的最早时间以及活动时间。

 

关键路径


原文:https://www.jianshu.com/p/1857ed4d8128

 

代码实现:

设一个工程有11项活动,9个事件,事件V1 ----- 表示整个工程开始,事件V9 ----- 表示整个工程结束。

每个事件的开始必须是它之前的活动已完成。例如:事件V2,V3,V4的开始必须是活动a1,a2,a3完成了。

这时我们会关注两个问题:

(1)完成整个项目需要多少时间?

(2)哪些活动是影响工程进度的关键?
定义:

关键路径:AOE-网中,从起点到终点最长的路径的长度(长度指的是路径上边的权重和)

关键活动:关键路径上的活动

AOE网:也叫边表示活动的网。AOE网是一个带权的有向无环图,其中顶点表示事件,弧表示活动,权表示活动持续的时间。

Ve[j] :表示事件j 的最早发生时间

VI[j]: 表示事件j 的最迟发生时间

e[i]:表示活动ai的最早开始时间

l[i]:表示活动ai的最迟开始时间
方法:

以邻接矩阵作为存储结构

1、从原点V1出发,令Ve[1] = 1,拓扑排序求各个顶点的Ve[i]

2、从Vn出发,令Vl[n] = Ve[n] ,逆拓扑排序求出各个顶点的Vl[i]

3、根据各顶点的Ve和Vl值,计算每条弧的e[i] 和 l[i],找出e[i] = l[i] 的关键活动

简单来说:

顺拓扑排序取大值求出Ve数组,逆拓扑序列取小值求出Vl数组,最后找出Ve[i] = Vl[i] 的顶点,即关键路径上的顶点,将这些顶点连接起来的路径叫关键路径。
实现:
手动实现:

 
代码实现:

    #include <iostream>
    #include <cstring>
    using namespace std;
    #define N 13
    int main()
    {
        int map[N][N]; //邻接矩阵
        // 初始化矩阵的值全部为0表示各个顶点间没有边连接
        for(int i = 0; i <= N-1; i++){
            for(int j = 0; j <= N-1; j++){
                map[i][j] = -1;
            }
        }
     
        int a,b,values;  //定义a,b,用来输入,values存储权值
        int v,l;  //顶点数和边数
     
        cout << "请输入顶点数:";
        cin >> v;
        cout << "请输入边数:";
        cin >> l;
        cout << "请输入边:" << endl;
     
        for(int i = 1; i <= l; i++){
                cin >> a >> b >> values;
                map[a][b] = values; // 表示顶点a指向顶点b的边,且权值为values
        }
     
        int k; //用于计算度数
        int ID[N],OD[N];  //储存各顶点的入度和出度
        int ve[N],vl[N];  //顺拓扑序列取大,逆拓扑序列取小
        memset(ve,0,sizeof(ve));  //初始化ve数组全为0
     
        for(int i = 1; i <= v; i++){  // 计算入度
            k = 0;
            for(int j = 1; j <= v; j++){
                if(map[j][i] != -1) //如果顶点j到顶点i有边,则顶点i的入度+1
                    k++;
            }
            ID[i] = k;
        }
        for(int i = 1; i <= v; i++){  //顺拓扑序列
            if(ID[i] == 0){
                for(int j = 1; j <= v; j++){
                    if(map[i][j] != -1){     //如果顶点j与顶点i有边,则删除这条边,并且顶点j的入度-1
                        if(ve[j] < map[i][j] + ve[i])  //取大值
                            ve[j] = map[i][j] + ve[i];
                        ID[j]--;
                    }
                }
            }
        }
        for(int i = 1; i <= v; i++){  // 计算出度
            k = 0;
            for(int j = 1; j <= v; j++){
                if(map[i][j] != -1)
                    k++;
            }
            OD[i] = k;
        }
     
        k = v;
        for(int i = 1; i <= v; i++)    //将 vl 数组全部初始化为ve最后一顶点的值
           vl[i] = ve[k];
     
        for(int i = k; i>=1; i--){  //逆拓扑序列
            if(OD[i] == 0){
                for(int j = 1; j <= v; j++){
                    if(map[j][i] != -1){
                        if(vl[j] > vl[i] - map[j][i])   //取小值
                            vl[j] = vl[i] - map[j][i];
                        OD[j]--;
                    }
                }
            }
        }
        cout << "****************************\n";
        cout << "Ve数组:";
        for(int i = 1; i <= k; i++){
            cout << ve[i] << " ";
        }
        cout << endl;
        cout << "Ve数组:";
        for(int i = 1; i <= k; i++){
            cout << vl[i] << " ";
        }
        cout << "\n****************************\n";
     
        cout << "关键路径:";
        for(int i = 1; i <= k - 1; i++){
            if(ve[i] == vl[i]){
                cout << i << "->";
            }
        }
        cout << k << endl;
        return 0;
    }

结果:

 

原文:https://blog.youkuaiyun.com/qq_37618797/article/details/81114696

关键路径的图形化展示通常应用于项目管理领域,尤其是在CPM(Critical Path Method)中。通过图形化界面可以清晰地表示出任务之间的依赖关系以及整个项目的最长路径,即关键路径。下面将从算法实现和图形化展示两个方面进行说明。 ### 算法实现 关键路径算法主要基于有向无环图(DAG, Directed Acyclic Graph),其中每个节点代表一个任务,边则表示任务间的先后顺序。为了找到关键路径,需要执行以下步骤: 1. **构建事件最早发生时间数组**:使用拓扑排序来初始化所有事件的最早开始时间为0,并按照拓扑序列依次计算各个事件的最早发生时间。 2. **计算事件最晚发生时间**:从最后一个事件开始逆向遍历整个图,确定每个事件的最晚发生时间而不影响整个项目的完成日期。 3. **确定活动松弛时间**:对于每一个活动,其松弛时间为该活动结束事件的最晚发生时间减去开始事件的最早发生时间再减去活动本身的持续时间。 4. **识别关键活动与关键路径**:如果某个活动的松弛时间为0,则这个活动就是关键活动,属于关键路径的一部分。 ### 图形化方法 在实现了上述算法之后,可以通过多种方式对结果进行可视化。一种常见的做法是利用网络图或者甘特图来进行展示: - **网络图**:在网络图中,节点代表任务,箭头表示任务之间的依赖关系。关键路径可以用不同的颜色或加粗线条突出显示。 - **甘特图**:这是一种条形图,它展示了项目的进度计划,横轴代表时间,纵轴代表任务。关键路径上的任务会以特定的方式标记出来,比如红色条形,以便于直观看到哪些任务是至关重要的。 ### 示例代码 这里提供了一个简单的Python示例,用于创建一个基本的关键路径问题并用matplotlib库绘制出对应的网络图。请注意这只是一个简化版的例子,实际应用中可能需要更复杂的逻辑来处理真实的数据结构。 ```python import matplotlib.pyplot as plt import networkx as nx # 创建一个空的有向图 G = nx.DiGraph() # 添加节点和边,这里假设我们有一个简单项目包含五个任务A,B,C,D,E edges = [('A', 'B'), ('B', 'C'), ('C', 'D'), ('D', 'E')] G.add_edges_from(edges) # 计算关键路径(在这个简化的例子中,直接指定关键路径) critical_path = ['A', 'B', 'C', 'D', 'E'] # 设置节点属性,为后续绘图做准备 pos = nx.spring_layout(G) # 定义布局 node_colors = ['red' if node in critical_path else 'blue' for node in G.nodes()] # 绘制图形 plt.figure(figsize=(10, 6)) nx.draw(G, pos, with_labels=True, node_size=700, node_color=node_colors, font_weight='bold') plt.show() ``` 这段代码首先导入了必要的库,然后定义了一个简单的项目模型,接着设置了关键路径,并最终使用`networkx`和`matplotlib`库将这些信息以图形的形式呈现出来。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值