关键路径 完整代码+解析

本文详细介绍了关键路径的概念,包括AOE网、AOV网、拓扑排序等,并给出了关键路径的编码步骤,包括建立连接表、计算最早发生时间和最迟发生时间以及找出关键活动。还提供了一个C语言的邻接表实现来演示关键路径的计算过程。
摘要由CSDN通过智能技术生成

关键路径

A.相关概念

  • AOE网:边表示活动,顶点表示事件,边上权值表示活动持续时间。

  • AOV网:顶点表示活动,弧表示活动间的优先关系。

  • 关键路径用AOE网,顶点表示活动,弧表示活动间的优先关系。

  • 入度:到达此顶点的路径条数。

  • 出度:从此顶点出去的路径条数。

  • 源点:入度为0,路径起始点。

  • 汇点:出度为0,路径终止点。

  • 拓扑序列:vi~vj间有一条路径,则这条路径就是拓扑序列。

  • 拓扑排序:对有向图构造拓扑序列的过程。

  • 对AOV网拓扑排序的思路:

    1.找到入度为0的顶点输出;

    2.删去此顶点,及以改顶点为尾的弧;

    3.重复1,2两步,直到没有入度为0的顶点。

  • 路径长度:路径上各个活动所持续的时间之和。

  • 关键路径:从源点到汇点具有最大长度的路径。

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

[link]:(62条消息) 图解:什么是关键路径?_ZenjaminFranklin的博客-CSDN博客

B.编码步骤

  • 1.建立连接表。

  • 2.用拓扑排序得最早发生时间etv[]

    a.初始化入度为0的栈stack(定义+开空间)。

    b.遍历顶点,将入度为0的顶点入栈。

    c.初始化etv[](开空间+初始值为0)。

    d.初始化拓扑序列栈stack2(后序用于求最晚发生时间ltv[])。

    e.遍历stack中的顶点,确定etv[]的值。

    etv[0]=0

    etv[k]=max{etv[i]+len<vi,vk>}

  • 3.根据事件的最早发生时间etv[]算事件的最迟发生时间ltv[]

    a.初始化ltv[],与etv[n-1]值相同。

    b.遍历stack2,求ltv的值。

    ltv[n-1]=etv[k]

    ltv[k]=min{ltv[j]-len<vk,vj>}

  • 4.求关键活动

    a.遍历每个点。

    b.确定活动最早发生时间ete,和活动最迟发生时间lte

    c.如果ete==lte则在关键路径上。

#include<stdio.h>
#include<stdlib.h>
​
#define MAXVEX 99
​
//储存结构
//边表结点
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;
​
//创建邻接表
void CreateALGraph(GraphAdjList* G)
{
     int i, j, k,w;
     EdgeNode* e;
     printf("输入顶点数和边数:\n");
     scanf("%d%d", &G->numVertexes, &G->numEdges);
     //建立顶点表
     printf("请输入顶点数据:\n");
     for (i = 0; i < G->numVertexes; i++)
     {
          scanf("%d", &G->adjList[i].data);
          G->adjList[i].firstedge = NULL;//边表置空
          G->adjList[i].in = 0;
     }
     //建立边表
     printf("输入i,j,w:\n");
     for (k = 0; k < G->numEdges; k++)
     {
          scanf("%d%d%d", &i, &j, &w);
          //存i顶点
          e = (EdgeNode*)malloc(sizeof(EdgeNode));//申请内存空间,生成边表结点
          e->adjvex = j;//邻接结点序号j
          e->next = G->adjList[i].firstedge;//e的指针指向当前顶点指向的结点
          e->weight = w;
          G->adjList[i].firstedge = e;//保存当前顶点的头指针
          //存j顶点
          e = (EdgeNode*)malloc(sizeof(EdgeNode));
          G->adjList[j].in=G->adjList[j].in+1;
          e->adjvex = i;
          //e->weight = w;
          e->next = G->adjList[j].firstedge;
          G->adjList[j].firstedge = e;
     }
}
​
//输出邻接表
void OutPutLink(GraphAdjList* GL)
{
     int i;
     EdgeNode* p;
     printf("图的邻接表表示如下:\n");
     printf("%6s%8s%12s\n", "编号", "顶点", "相邻边编号");
     for (i = 0; i < GL->numVertexes; i++)
     {
          printf("%4d %8d", i, GL->adjList[i].data);
          for (p = GL->adjList[i].firstedge; p != NULL; p = p->next)printf("%4d", p->adjvex);
          printf("\n");
     }
}
​
//关键路径
int* etv;//事件最早发生时间
int *ltv;//事件最迟发生时间
int *stack2;//储存拓扑序列的栈,用于计算ltv
int top2;//stack2栈顶指针
//拓扑排序
#define OK 1
#define ERROR 0
typedef int Status;
//若GL无回路,则输出拓扑序列并返回1
Status TopologicalSort(graphAdjList GL)
{
     EdgeNode* e;
     int i, k;
     int gettop;//临时储存栈顶元素
     int* stack;//储存入度为0顶点的栈
     int top = 0;//stack栈顶指针
     int count = 0;//统计输出顶点的个数
​
     //初始化stack
     stack = (int*)malloc(GL->numVertexes * sizeof(int));
     //入度为0的顶点入栈
     for (i = 0; i < GL->numVertexes; i++)
     {
          if (GL->adjList[i].in == 0)
          {
               stack[++top] = i;
          }
     }
​
     //初始化etv
     etv = (int*)malloc(GL->numVertexes * sizeof(int));
     //事件最早发生数组初始化为0
     for (i = 0; i < GL->numVertexes; i++)
     {
          etv[i] = 0;
     }
​
     //初始化序列栈stack2
     stack2 = (int*)malloc(GL->numVertexes * sizeof(int));
     top2 = 0;
​
     //清空入度为0的栈
     while (top != 0)
     {
          gettop = stack[top--];//临时保存栈顶元素
          count++;//计数出栈的顶点
          stack2[++top2] = gettop;//将弹出的顶点压入拓扑序列栈
          for (e = GL->adjList[gettop].firstedge; e; e = e->next)//遍历与gettop顶点相关联的邻接顶点
          {
               k = e->adjvex;//临时储存邻接顶点域
               //判断是否有需要入栈的新结点
               if (!(--GL->adjList[k].in))//删除顶点gettop后,判断是否出现新的入度为0的点,有则入栈
               {
                    stack[++top] = k;
               }
               //更新最早发生时间etv的值
               if ((etv[gettop] + e->weight) > etv[k])
               {
                    etv[k] = etv[gettop] + e->weight;
               }
          }
     }
     if (count < GL->numVertexes)
     {
          return ERROR;
     }
     else
     {
          return OK;
     }
}
//求关键路径,输出G的各项关键活动
void CriticalPath(graphAdjList GL)
{
     EdgeNode* e;
     int i, j, k, gettop;
     int ete;//活动最早发生时间
     int lte;//活动最迟发生时间
​
     TopologicalSort(GL);//计算拓扑序列,得etv和stack2的值
​
     //初始化ltv
     ltv = (int*)malloc(GL->numVertexes * sizeof(int));
     for (i = 0; i < GL->numVertexes; i++)
     {
          ltv[i] = etv[GL->numVertexes - 1];
     }
​
     //计算ltv
     while (top2 != 0)
     {
          gettop = stack2[top2--];
          for (e = GL->adjList[gettop].firstedge; e; e = e->next)//遍历gettop的邻接顶点
          {
               k = e->adjvex;
               if (ltv[k] - e->weight < ltv[gettop])//求各邻接顶点最晚发生时间
               {
                    k = e->adjvex;
                    if (ltv[k] - e->weight < ltv[gettop])
                    {
                         ltv[gettop] = ltv[k] - e->weight;
                    }
               }
          }
     }
     //求ete,lte和关键路径
     for (j = 0; j < GL->numVertexes; j++)
     {
          for (e = GL->adjList[j].firstedge; e; e = e->next)
          {
               k = e->adjvex;
               ete = etv[j];//活动最早发生时间
               lte = ltv[k] - e->weight;//活动最迟发生时间
               if (ete == lte)
               {
                    printf("<v%d - v%d> length: %d\n", GL->adjList[j].data, GL->adjList[k].data, e->weight);
               }
          }
     }
}
​
​
​
int main()
{
     GraphAdjList* GL;
     if (!(GL = (GraphAdjList*)malloc(sizeof(GraphAdjList))))return 0;
     CreateALGraph(GL);
     OutPutLink(GL);
     CriticalPath(GL);
     return 0;
}
  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值