关键路径算法

相关概念:

  (1)AOE (Activity On Edges)网络 如果在无有向环的带权有向图中用有向边表示一个工程中的各项活动(Activity),用边上的权值表示活动的持续时间(Duration),用顶点表示事件(Event),则这样的有向图叫做用边表示活动的网络,简称AOE (Activity On Edges)网络。AOE网是一个带权的有向无环图。AOE网络在某些工程估算方面非常有用。例如,可以使人们了解:

  a、完成整个工程至少需要多少时间(假设网络中没有环)?

  b、为缩短完成工程所需的时间, 应当加快哪些活动?

  (2)关键路径(Critical Path) 在AOE网络中, 有些活动顺序进行,有些活动并行进行。从源点到各个顶点,以至从源点到汇点的有向路径可能不止一条。这些路径的长度也可能不同。完成不同路径的活动所需的时间虽然不同,但只有各条路径上所有活动都完成了,整个工程才算完成。因此,完成整个工程所需的时间取决于从源点到汇点的最长路径长度,即在这条路径上所有活动的持续时间之和。这条路径长度最长的路径就叫做关键路径(Critical Path)。

  (3)由于实际工程只有一个开始点和一个结束点,因此AOE网存在唯一的入度为0的开始点(又称源点)和唯一的出度为0的结束点(又称汇点)

参数定义:

  (1)事件的最早发生时间 etv(earliest time of vertex):即顶点Vk的最早发生时间。

  (2)事件的最晚发生时间 ltv(latest time of vertex):即顶点Vk的最晚发生时间,也就是每个顶点对应的事件最晚需要开始的时间,超出此事件将会延误整个工期。

  (3)活动的最早开工时间 ete(earliest time of edge):即弧ak的最早发生时间。

  (4)活动的最晚开工时间 lte(latest time of edge):即弧ak的最晚发生时间,也就是不推迟工期的最晚开工时间。

代码实现:

#include <stdio.h>
#include <stdlib.h>
#define MAXVERTEX 20
#define INCSIZE 10
typedef int ElemType;
typedef char VertexType;
typedef int EdgeType;
typedef struct EdgeNode
{
    int adjvex;
    EdgeType weight;
    struct EdgeNode *next;
}EdgeNode;

typedef struct VertexNode
{
    VertexType data;
    int in;
    struct EdgeNode *first;
}VertexNode,AdjList[MAXVERTEX];

typedef struct AdjGraphList
{
    AdjList adjList;
    int numVertex;
    int numEdge;
}AdjGraphList;

typedef struct SqStack
{
    ElemType *base;
    ElemType *top;
    int stackSize;
}SqStack;
typedef struct SqStack *LinkStack;
static int etv[MAXVERTEX];                                          //顶点(事件)最早开始时间
static int ltv[MAXVERTEX];                                          //顶点(事件)的最晚开始时间
static int ete;                                                     //弧(活动)的最早开始时间
static int lte;                                                     //弧(活动)的最晚开始时间
//建立一个栈
void InitStack(SqStack *s)
{
    s->base = (ElemType *)malloc(MAXVERTEX*sizeof(ElemType));
    if(!s->base)
        return;
    s->top = s->base;
    s->stackSize = MAXVERTEX;
}
void Push(SqStack *s,ElemType *e)
{
    if(s->top - s->base >= s->stackSize - 1)
    {
        s->base = (ElemType *)realloc(s->base,(s->stackSize + INCSIZE)*sizeof(ElemType));
        if(!s->base)
            return;
    }
    *(s->top) = *e;
    s->top++;
}
void Pop(SqStack *s,ElemType *e)
{
    if(s->top == s->base)
    {
        return;
    }
    s->top--;
    *e = *(s->top);
}
int StackLen(SqStack *s)
{
    return (s->top - s->base);
}

void CreateAdjGraphList(AdjGraphList *G)                                 //构造图,输入图中数据
{
    int i = 0,j = 0,k = 0,w = 0;
    int indegree;
    EdgeNode *p;
    VertexType c;
    printf("请输入顶点数和边数,中间用逗号隔开:\n");
    scanf("%d,%d",&G->numVertex,&G->numEdge);
    fflush(stdin);
    printf("请输入各个顶点存放的值,以及他们的入度,输入#表示结束 :\n");
    scanf("%c,%d",&c,&indegree);
    while(i < G->numVertex)
    {
        if(c == ‘#‘)
            break;
        G->adjList[i].data = c;
        G->adjList[i].in = indegree;
        G->adjList[i].first = NULL;
        i++;
        fflush(stdin);
        printf("请输入各个顶点存放的值,以及他们的入度,输入#表示结束 :\n");
        scanf("%c,%d",&c,&indegree);
    }
    fflush(stdin);
    for(k = 0;k < G->numEdge;k++)
    {
        printf("请输入边<Vi-Vj>所依附顶点的下标 i 和 j,以及权值w:\n");
        scanf("%d,%d,%d",&i,&j,&w);
        p = (EdgeNode *)malloc(sizeof(EdgeNode));
        p->adjvex = j;
        p->weight = w;
        p->next = G->adjList[i].first;
        G->adjList[i].first = p;
    }
}
void Findetv(AdjGraphList *G,SqStack *s1,SqStack *s2)
{
    int i,k,count = 0;
    ElemType e;
    EdgeNode *p;
//    SqStack s1,s2;
//    InitStack(&s1);
//    InitStack(&s2);
    for(i = 0;i < G->numVertex;i++)                             //初始化etv = 0
    {
        etv[i] = 0;
        if(G->adjList[i].in == 0)
        {
            Push(s1,&i);
        }
    }
    while(StackLen(s1))
    {
        Pop(s1,&e);
        count++;
        Push(s2,&e);                                          //压入栈s2
        p = G->adjList[e].first;
        while(p)
        {
            k = p->adjvex;
            G->adjList[k].in = G->adjList[k].in -1;
            if(G->adjList[k].in == 0)
            {
                Push(s1,&k);
            }
            if(etv[k] < etv[e] + p->weight)                //构造数组etv
            {
                etv[k] = etv[e] + p->weight;
            }
            p = p->next;
        }
    }
    printf("\n\netv数组为:\n");                         //测试
    for(i = 0;i < G->numVertex;i++)
    {
        printf("%d ",etv[i]);
    }
    printf("\n");
    if(count != G->numVertex)
    {
        printf("存在回路,无法找到关键路径!\n");
        return;
    }
    else
    {
        return;
    }
}
void FindCriticalPath(AdjGraphList *G,SqStack *s2)
{
    int i = 0,k = 0;
    ElemType e;
    EdgeNode *p,*q;
    Pop(s2,&e);
    for(i = 0;i < G->numVertex;i++)   //初始化顶点最晚开始时间
    {
        ltv[i] = etv[e];     //拓扑排序中最晚弹出的数据的etv最大,也就是完成这个有向无环图所用的时间
    }
    Push(s2,&e);
    while(StackLen(s2))
    {
        Pop(s2,&e);
        p = G->adjList[e].first;
        while(p)
        {
            k = p->adjvex;
            if( ltv[e] > ltv[k] - p->weight )
            {
                ltv[e] = ltv[k] - p->weight;
            }
            p = p->next;
        }
    }
    printf("\nltv数组为:\n");
    for(i = 0;i < G->numVertex;i++)
    {
        printf("%d ",ltv[i]);
    }
    printf("\n\n关键路径包含的弧如下: \n");
    for(i = 0;i < G->numVertex;i++)
    {
        q = G->adjList[i].first;
        while(q)
        {
            k = q->adjvex;
            ete = etv[i];       //由于顶点(事件)的持续过程为0,所以顶点的最早开始时间也是以这个顶点为弧尾的弧的最早开始时间
            lte = ltv[k] - q->weight;
            if(ete == lte)
            {
                printf("<%c,%c> 权值: %d \n",G->adjList[i].data,G->adjList[k].data,q->weight);
            }
            q = q->next;
        }

    }
}
int main()
{
    AdjGraphList G;
    SqStack s1,s2;
    InitStack(&s1);
    InitStack(&s2);
    CreateAdjGraphList(&G);
    Findetv(&G,&s1,&s2);
    FindCriticalPath(&G,&s2);
    return 0;
}

  

时间: 2024-11-07 07:08:13

关键路径算法的相关文章

[从今天开始修炼数据结构]无环图的应用 —— 拓扑排序和关键路径算法

上一篇文章我们学习了最短路径的两个算法.它们是有环图的应用.下面我们来谈谈无环图的应用. 一.拓扑排序 博主大学学的是土木工程,在老本行,施工时很关键的节约人力时间成本的一项就是流水施工,钢筋没绑完,浇筑水泥的那帮兄弟就得在那等着,所以安排好流水施工,让工作周期能很好地衔接就很关键.这样的工程活动,抽象成图的话是无环的有向图. 在表示工程的有向图中,用顶点表示活动,弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,成为AOV网(Active On Vertex Network) ※ 若在

关键路径算法(PAT How Long Does It Take (25))

#include<iostream> #include<stack> #include<cstring> #include<string> #include<algorithm> using namespace std ; #define MAXN 100 int map[MAXN][MAXN] ; int in_cout[MAXN] ; int e_time[MAXN] ; int arry[MAXN] ; int n , e , n_s =

48. 蛤蟆的数据结构笔记之四十八的有向无环图的应用关键路径

48. 蛤蟆的数据结构笔记之四十八的有向无环图的应用关键路径 本篇名言:"富贵不淫贫贱乐 ,男儿到此是豪雄.-- 程颢" 这次来看下有向无环图的另一个应用关键路径. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47135061 1.  关键路径 与AOV-网相对应的是AOE-网(Activity On Edge)即边表示活动的网.AOE-网是一个带权的有向无环图,其中,顶点表示事件(Event),弧表示活动,权表

数据结构 图 关键路径

数据结构图之六(关键路径) [1]关键路径 在我的经验意识深处,“关键”二字一般都是指临界点. 凡事万物都遵循一个度的问题,那么存在度就会自然有临界点. 关键路径也正是研究这个临界点的问题. 在学习关键路径前,先了解一个AOV网和AOE网的概念: 用顶点表示活动,用弧表示活动间的优先关系的有向图: 称为顶点表示活动的网(Activity On Vertex Network),简称为AOV网. 与AOV网对应的是AOE(Activity On Edge)网即边表示活动的网. AOE网是一个带权的有

数据结构(八) AOV网的关键路径(Swift面向对象版)

上篇博客我们介绍了AOV网的拓扑序列,请参考<数据结构(七) AOV网的拓扑排序(Swift面向对象版)>.拓扑序列中包括项目的每个结点,沿着拓扑序列将项目进行下去是肯定可以将项目完成的,但是工期不是最优的.因为拓扑序列是一个串行序列,如果按照该序列执行项目,那么就是串行执行的.我们知道在一个项目中的一些子工程是可以并行来完成的,这也就类似我们的多线程.今天我们要解决的问题就是找出一个关键路径,是工期最优并保证工程的完成.什么是关键路径,我们在下方会进行详细介绍. 一.关键路径概述 在聊关键路

关键路径问题

关键路径问题 1.拓扑排序主要是为了解决一个工程能否顺利进行的问题,但有时我们还需要解决工程完成所需要的最短时间问题.我们如果对一个流程图获得最短时间,就需要分析它们的拓扑关系,并且找到当中的最关键流程,这个流程的时间就是最短时间. 2.AOV网:在一个表示工程的带权有向图中,用顶点表示事件,用有向边表示活动,用边上的权值表示活动持续的时间,这种有向图的边表示活动的网,我们称之为AOE网.AOE网中没有入边的顶点称为起点或者源点,没有出边的顶 点成为终点或者汇点.由于一个工程,总有一个开始,一个

浅谈数据结构-关键路径

上一章节讲解了拓扑排序问题,拓扑排序是解决一个工程能否顺序解决的问题,本质是一个广度层次遍历的过程,通过记录顶点入度问题,进行逐步输出的工作.在实际生活中,往往是求解工程完成需要最短时间问题.比如生活中生产一辆汽车,需要生产各种各样的零件,最终组装成车.例如生产轮子0.5天,发动机3天,底盘2天,其他部件2天,集中全部零件0.5天,组装需要2天.请问组装一辆汽车,最短需要多长时间.根据前面描述,我们构造这样的AOV网络图,一看便知. 通过网络中,我们很清晰的知道,关键路径是5.5,如果发动机提高

基于AOE网的关键路径的求解

[1]关键路径 在我的经验意识深处,“关键”二字一般都是指临界点. 凡事万物都遵循一个度的问题,那么存在度就会自然有临界点. 关键路径也正是研究这个临界点的问题. 在学习关键路径前,先了解一个AOV网和AOE网的概念: 用顶点表示活动,用弧表示活动间的优先关系的有向图: 称为顶点表示活动的网(Activity On Vertex Network),简称为AOV网. 与AOV网对应的是AOE(Activity On Edge)网即边表示活动的网. AOE网是一个带权的有向无环图. 网中只有一个入度

《软件项目管理》课程知识总结

   这篇文章是结合<软件项目管理>课程知识进行的总结,我也不知道自己为什么要总结这篇文章,很多事情没有原因就做了,希望对大家有所帮助,尤其是上这门课的同学吧!有时候也在想写这样的文章到底有没有用,估计用处不大,但没办法兴趣使然~     --吾亦无他,唯心向尓     (By:Eastmount 2014-11-25 下午5点 http://blog.csdn.net/eastmount/) 一. 什么是项目管理?     随着软件危机(Software Crisis)带来软件代价高.难于控