图-关键路径算法

关键路径(CriticalPath)

我们把路径上各个活动所持续时间之和称为路径长度,从源点到汇点具有最大长度的路径叫关键路径,在关键路径上的活动叫做关键活动.。

AOV网和AOE网

在这里插入图片描述

算法用到的4个关键变量:

  1. etv (Earliest time of vertex):事件的最早发生时间,即顶点k的最早发生时间
  2. ltv(Latest time of vertex):事件最晚发生时间,即顶点k的最晚发生时间
  3. ete(Earliest time of edge):活动最早开工时间,即弧k的最早发生时间
  4. lte(Latest time of edge):活动最晚开工时间,即弧k的最晚发生时间

我们可以根据1,2求得3,4,再根据ete[k] 是否与lte[k]相等来判断k是否为关键活动

etv[k] 与 ltv[k]的计算公式:

在这里插入图片描述
在这里插入图片描述

关键路径算法借助到了改进过的拓扑排序算法,多了一个stack2栈,用来存放倒过来的拓扑序列(由于栈是后进先出的),同时计算生成了etv数组,计算公式如上图。

#include 
#include 
#define OK 1
#define ERROR 0
#define STATUS int 
typedef struct EdgeNode 
{
    int adjvex;/*邻接点域*/
    int weight;/*权值*/
    struct EdgeNode *next;
}EdgeNode;

typedef struct VertexNode
{
    int in; /*入度*/
    int data;
    EdgeNode *firstEdge;
}VertexNode, AdjList[MAXVEX];

typedef struct 
{
    AdjList adjList;
    int numVertexes, numEdges;
}*GraphAdjList, graphAdjList;

/*改进的辅助拓扑排序算法*/
/*需要定义几个全局变量*/
int *etc, *ltv;
int *stack2;/*stack2存放拓扑序列的栈*/
int top2; /* top2必须是全局变量,以为在辅助算法和主算法都用到了 */
Status TopologicalSort(GraphAdjList G)
{
    EdgeNode *e;
    int i, k, gettop;
    int top = 0;
    int count = 0;
    int top2 = 0;/*初始化stack2数组的栈顶指针*/
    int *stack;

    stack = (int *)malloc(G->numVertexes * sizeof(int));
    etv = (int *)malloc(G->numVertexes * sizeof(int));/*初始化*/
    stack2 = (int *)malloc(G->numVertexes * sizeof(int));/*初始化*/

    for(i = 0; i < G->numVertexes; i++)
    {
        etv[i] = 0;/*每个事件的最早发生时间,都先初始化为0*/

        if(0 == G->adjList[i].in)
        {
            stack[++top] = i;/*如果入度为0,入栈*/
        }
    }

    while(top != 0)
    {
        gettop = stack[top--];
        count++;
        stack2[++top2] = gettop;/*stack2栈用于保存拓扑序列,后进先出,所以是倒过来的*/

        for(e = G->adjList[gettop].firstEdge; e; e = e->next)
        {
            k = e->adjvex;
            if(!(--G->adjList[k].in))
            {
                stack[++top] = k;
            }

            if((etv[gettop] + e->weight) > etv[k])
            {   
                /*gettop就是刚刚弹出的顶点,k就是与gettop相邻的顶点 找一个大的值保存*/
                /*v[gettop] ----[weight]----> v[k]*/
                /*确定顶点k事件的最早发生时间并且保存以供后续的关键路径算法使用。*/
                etv[k] = etv[gettop] + e->weight;
            }
        }
    }

    if(count < G->numVertexes)
    {
        return ERROR;
    }else
    {
        return OK;
    }
}

void CriticalPath(GraphAdjList G)
{
    EdgeNode *e;
    int i, gettop, k, j;
    int ete, lte;
    TopologicalSort(G);
    ltv = (int *)malloc(G->numVertexes * sizeof(int))
    for(i = 0; i < G->numVertexes; i++)
    {
        ltv[i] = etv[G->numVertexes-1];/*所有事件的最晚发生时间都初始化为 拓扑序列最后一个顶点事件的最早发生时间*/
    }
    /*从后往前开始计算ltv,ltv的计算公式在图中给出*/
    while(top2 != 0)
    {
        gettop = stack2[top2--];
        for(e = G->adjList[gettop].firstedge; e; e = e->next)
        {
            k = e->adjvex;
            if(ltv[k] - e->weight < ltv[gettop])
            {
                /* v[gettop] -----[weight]------> v[k] */
                itv[gettop] = ltv[k] - e->weight;
            }
        }
    }
    for(j = 0; j < G->numVertexes; j++)
    {
        for(e = G->adjList[j].firstedge; e; e = e->next)
        {
            k = e->adjvex;
            ete = etv[j]; /*活动最早开始时间就等于事件最早发生时间*/
            lte = ltv[k] - e->weight; /*活动最晚开始时间等于 后继事件最晚发生时间 减去 活动的持续时间(权值)*/
            if(ete == lte)
            {
                /*输出打印*/
                printf(" length: %d, ", G->adjList[j].data, G->adjList[k].data, e->weight);
            }
        }
    }
}

你可能感兴趣的:(图-关键路径算法)