【C语言】关键路径算法

AOE网

  • 在一个表示工程的带权有向图中,用顶点表示事件,用有向边表示活动,用边上的权值表示活动的持续时间,这种有向图的边表示活动的网,我们称之为AOE网。
  • 把AOE网中没有入边的顶点称为始点或源点,没有出边的点称为终点或汇点。由于一个工程总有一个开始,一个结束,所以正常情况下,AOE网只有一个源点,一个汇点。
  • AOE网具有明显的工程特性,如在某顶点所代表的事件发生后,从该顶点出发的各活动才能开始。只有在进入某顶点的各活动都已经结束,该顶点所代表的事件才能发生。
  • 我们把路径上各个活动所持续的时间之和称为路径长度,从源点到汇点具有最大长度的路径叫关键路径,在关键路径上的活动叫关键活动。
    在这里插入图片描述

关键路径算法

实现步骤

我们定义如下几个参数:

  • 事件的最早发生时间etv(earliest time of vertex),即顶点Vk的最早发生时间。
  • 事件的最晚发生时间ltv(latest time of vertex),即顶点Vk的最晚发生时间。
  • 活动的最早发生时间ete(earliest time of edge),即弧ak的最早发生时间。
  • 活动的最晚发生时间lte(latest time of edge),即弧ak的最晚发生时间。

1、在求关键路径之前,需要先调用一次拓扑序列算法的代码来计算etv和拓扑序列列表。
2、通过对拓扑序列列表出栈,计算得到ltv。
3、根据etv和ltv计算每个弧的ete和lte,若ete等于lte则该路径为关键路径。

代码实现

/*
 * @Author: Xyh4ng
 * @Date: 2022-11-24 14:49:32
 * @LastEditors: Xyh4ng
 * @LastEditTime: 2022-11-24 16:35:29
 * @Description:
 * Copyright (c) 2022 by Xyh4ng 503177404@qq.com, All Rights Reserved.
 */
#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 500
#define INFINITY 10000

typedef struct
{
    int vexs[MAXSIZE];
    int arc[MAXSIZE][MAXSIZE];
    int numVertexes, numEdges;
} MGraph;

// 边表结点
typedef struct EdgeNode
{
    int adjVex;
    int weight;
    struct EdgeNode *next;
} EdgeNode;

// 顶点表结点
typedef struct VertexNode
{
    int in;
    int data;
    EdgeNode *firstEdge;
} VertexNode, AdjList[MAXSIZE];

typedef struct GraphAdjList
{
    AdjList adjList;
    int vertexNums, edgeNums;
} GraphAdjList;

// 构建图
void CreateMGraph(MGraph *G)
{
    G->numVertexes = 10;
    G->numEdges = 13;

    for (int i = 0; i < G->numVertexes; i++)
    {
        G->vexs[i] = i;
    }
    for (int i = 0; i < G->numVertexes; i++)
    {
        for (int j = 0; j < G->numVertexes; j++)
        {
            if (i == j)
                G->arc[i][j] = 0;
            else
                G->arc[i][j] = INFINITY;
        }
    }

    G->arc[0][1] = 3;
    G->arc[0][2] = 4;
    G->arc[1][3] = 5;
    G->arc[1][4] = 6;
    G->arc[2][3] = 8;
    G->arc[2][5] = 7;
    G->arc[3][4] = 3;
    G->arc[4][6] = 9;
    G->arc[4][7] = 4;
    G->arc[5][7] = 6;
    G->arc[6][9] = 2;
    G->arc[7][8] = 5;
    G->arc[8][9] = 3;
}

// 利用邻接矩阵构建邻接表
void InitGraphADjList(MGraph *G, GraphAdjList *GL)
{
    GL->vertexNums = G->numVertexes;
    GL->edgeNums = G->numEdges;

    for (int i = 0; i < G->numVertexes; i++) /* 读入顶点信息,建立顶点表 */
    {
        GL->adjList[i].in = 0;
        GL->adjList[i].data = G->vexs[i];
        GL->adjList[i].firstEdge = NULL; /* 将边表置为空表 */
    }

    for (int i = 0; i < G->numVertexes; i++) /* 建立边表 */
    {
        for (int j = 0; j < G->numVertexes; j++)
        {
            if (G->arc[i][j] != 0 && G->arc[i][j] < INFINITY)
            {
                EdgeNode *e = (EdgeNode *)malloc(sizeof(EdgeNode));
                e->adjVex = j; /* 邻接序号为j  */
                e->weight = G->arc[i][j];
                e->next = GL->adjList[i].firstEdge; /* 将当前顶点上的指向的结点指针赋值给e */
                GL->adjList[i].firstEdge = e;       /* 将当前顶点的指针指向e  */
                GL->adjList[j].in++;
            }
        }
    }
}

int TopologicalSort(GraphAdjList *GL, int *etv, int *stackSort, int *topSort)
{
    int count = 0; // 用于统计输出顶点的个数
    int *stack = (int *)malloc(sizeof(int) * GL->vertexNums);
    int top = 0;
    for (int i = 0; i < GL->vertexNums; i++)
    {
        if (GL->adjList[i].in == 0)
        {
            stack[++top] = i;
        }
    }
    while (top != 0)
    {
        int k = stack[top--];
        stackSort[++(*topSort)] = k;
        count++;
        EdgeNode *p = GL->adjList[k].firstEdge;
        while (p != NULL)
        {
            GL->adjList[p->adjVex].in--;
            if (etv[k] + p->weight > etv[p->adjVex])
                etv[p->adjVex] = etv[k] + p->weight;
            if (GL->adjList[p->adjVex].in == 0)
            {
                stack[++top] = p->adjVex;
            }
            p = p->next;
        }
    }
    if (count < GL->vertexNums) // 若输出的顶点个数少了,则说明这个网存在环路,不是AOV网
        return 0;
    else
        return 1;
}

void CriticalPath(GraphAdjList *GL, int *etv, int *stackSort, int *topSort)
{
    int *ltv = (int *)malloc(sizeof(int) * GL->vertexNums); // 事件最晚开始时间
    int ete;                                                // 活动最早开始时间 = 与活动相关的事件的最早开始时间
    int lte;                                                // 活动最晚开始时间 = 指向活动的最晚开始时间 - 弧的权值
    for (int i = 0; i < GL->vertexNums; i++)
    {
        ltv[i] = etv[stackSort[(*topSort)]];
    }
    // 计算各事件的最晚开始时间
    while ((*topSort) != 0)
    {
        int k = stackSort[(*topSort)--];
        EdgeNode *p = GL->adjList[k].firstEdge;
        while (p != NULL)
        {
            if (ltv[p->adjVex] - p->weight < ltv[k])
                ltv[k] = ltv[p->adjVex] - p->weight;
            p = p->next;
        }
    }
    // 计算活动最早开始时间,活动最晚开始时间,寻找关键路径
    for (int i = 0; i < GL->vertexNums; i++)
    {
        ete = etv[i];
        EdgeNode *p = GL->adjList[i].firstEdge;
        while (p != NULL)
        {
            lte = ltv[p->adjVex] - p->weight;
            if (ete == lte)
            {
                printf("<V%d - V%d> length: %d\n", GL->adjList[i].data, GL->adjList[p->adjVex].data, p->weight);
            }
            p = p->next;
        }
    }
}

int main()
{
    MGraph *G = (MGraph *)malloc(sizeof(MGraph));
    CreateMGraph(G);
    GraphAdjList *GL = (GraphAdjList *)malloc(sizeof(GraphAdjList));
    InitGraphADjList(G, GL);
    // 为了获得各事件的最早开始时间,需要先对AOE网进行一次拓扑排序
    int *etv = (int *)malloc(sizeof(int) * GL->vertexNums); // 事件最早开始时间
    for (int i = 0; i < GL->vertexNums; i++)
    {
        etv[i] = 0;
    }
    int *stackSort = (int *)malloc(sizeof(int) * GL->vertexNums);
    int *topSort = (int *)malloc(sizeof(int));
    *topSort = 0;
    int flag = TopologicalSort(GL, etv, stackSort, topSort);
    if (flag == 1)
        CriticalPath(GL, etv, stackSort, topSort);
    return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值