关键路径--经典算法

探寻


AOE网

用顶点表示事件,弧表示活动,弧上的权值表示活动持续的时间的有向图叫AOE(Activity On Edge Network)网。在建筑学中也称为关键路线。AOE网常用于估算工程完成时间。例如:
关键路径--经典算法_第1张图片 图1
图1 是一个网。其中有9个事件v1,v2,…,v9;11项活动a1,a2,…,a11。每个事件表示在它之前的活动已经完成,在它之后的活动可以开始。如 v1表示整个工程开始,v9 表示整个工程结束。V5表示,活动a2和a3已经完成,活动a7和a8可以开始。与每个活动相联系的权表示完成该活动所需的时间。如活动a1需要6个时间单位可以完成、



AOE网性质

只有在某顶点所代表的事件发生后,从该顶点出发的各有向边所代表的活动才能开始。
只有在进入某一顶点的各有向边所代表的活动都已经结束,该顶点所代表的事件才能发生。表示实际工程计划的AOE网应该是无环的,并且存在唯一的入度过为0的开始顶点和唯一的出度为0的完成顶点。


关键路径

关键路径--经典算法_第2张图片 图2
这时从开始顶点到达完成顶点的所有路径都是关键路径。
一个AOE网的关键路径可以不止一条,如图7.24的AOE网中有二条关键路径,(v1,v2,v5,v7,v9 ) 和 (v1,v2,v5,v8,v9 )它们的路径长度都是24。
如图2所示:

研究的问题

(1) 完成整个工程至少需要多少时间;
(2) 哪些活动是影响工程的关键。
1956年,美国 杜邦公司提出 关键路径法,并于1957年首先用于1000万美元化工厂建设,工期比原计划缩短了4个月。杜邦公司在采用关键路径法的一年中,节省了100万美元。

关键路径术语

(1) 关键路径:从源点到汇点的路径长度最长的路径叫关键路径;
(2) 活动开始的最早时间e(i);
(3) 活动开始的最晚时间l(i) 定义e(i)=l(i)的活动叫关键活动;
(4) 事件开始的最早时间ve(i);
(5) 事件开始的最晚时间vl(i)。
设活动ai由弧(即从顶点j到k)表示,其持续时间记为dut(),则
e(i)=ve(j)
l(i)=vl(k)-dut()
求ve(i)和vl(j)分两步:
1、从ve(1)=0开始向前递推
ve(j)=Max{ ve(i)+dut() }
T,2<=j<=n
其中,T是所有以j为弧头的弧的集合。
2、 从vl(n)=ve(n)开始向后递推
vl(i)=Min{ vl(j)-dut() }
S,1<=i<=n-1
其中,S是所有以i为弧尾的弧的集合。
两个递推公式是在拓扑有序和逆拓扑有序的前提下进行。
就如上面的图1:可有下表:
关键路径--经典算法_第3张图片


求关键路径的算法
(1) 输入e条弧,建立AOE网的存储结构;
(2) 从源点v1出发,令ve(1)=0,求 ve(j) 2<=j<=n;
(3) 从汇点vn出发,令vl(n)=ve(n),求 vl(i) 1<=i<=n-1;
(4) 根据各顶点的ve和vl值,求每条弧s(活动)的最早开始时间e(s)和最晚开始时间l(s),其中e(s)=l(s)的为关键活动。
求关键路径是在 拓扑排序的前提下进行的,不能进行拓扑排序,自然也不能求关键路径。

算法分析

(1) 求关键路径必须在拓扑排序的前提下进行,有环图不能求关键路径;
(2) 只有缩短关键活动的工期才有可能缩短工期;
(3) 若一个关键活动不在所有的关键路径上,减少它并不能减少工期;
(4) 只有在不改变关键路径的前提下,缩短关键活动才能缩短整个工期。
测试数据:
第一行表示顶点数和弧数;后面每一行就是权值,弧尾,弧头;

6 8

3 12

2 13

2 24

3 25

4 34

3 36

2 46

1 56



代码:可能在过程中需要知道拓扑排序,如果不知道的可以在我的另一篇文章中有介绍,此处的数据之间有点绕,可以好好的自己推一下,懂了之后就是很简单的算法;这里我使用的是C++的STL辅助,如果,有不懂的读者可以提前了解,其实,一起可以自己用C语言写一下啦,只是有点麻烦啦,什么队列栈呀的,都可以自己用数组模拟,知识在C++的STL中都有了,那还模拟啥呢,
#include 
#include 
#include 
#include 
#include 
#define NUM 20
using namespace std;

struct Info{
    int num;
    int value;
    Info(){}
    Info(int x,int y):num(x),value(y){}//构造函数
};
int indree[NUM]={0};
int N,M;//表示顶点数和边数;


vector > Graph(NUM);
stack T;//用来储存拓扑排序的顶点,用来逆序输出;

int Ve[NUM];
int Vl[NUM];


    //拓扑排序求出事件 的最早发生时间Ve(j)和最迟发生时间Vl(j);

bool tuopsort()
{
    int count = 0;
    stack q;
    memset(Ve, 0, sizeof(Ve));
    for(int i = 1;i<=N;i++)
        if(!indree[i])
            q.push(i);

    while(!q.empty()){
        int t = q.top();
        q.pop();
        count++;
        T.push(t);
        for(list::iterator it =  Graph[t].begin(); it!=Graph[t].end();it++){
            int k = it->num;
            if(!(--indree[k]))
                q.push(k);
            Ve[k] = max(Ve[k],Ve[t]+it->value);//不断更新里面的最大值;
        }
    }
    if(count::iterator it =  Graph[t].begin(); it!=Graph[t].end();it++){
            int k = it->num;
            Vl[t] = min(Vl[t],Vl[k]-it->value);//也是不断的更新;
        }
    }
//    for(int i = 1;i<=N;i++){
//        cout <::iterator it =  Graph[i].begin(); it!=Graph[i].end();it++){
            int k = it->num;
            ee= Ve[i];
            el = Vl[k]-it->value;
            int flag = (ee==el)?1:0;
            cout <v"<value<<" "<>N>>M;
    for(int i=1;i<=M;i++){
        int v,f,e;
        cin>>v>>f>>e;
        if(f!=e)
            {Graph[f].push_front(Info(e,v));indree[e]++;}
    }

//    cout <<"图的邻接表储存:"<



你可能感兴趣的:(算法)