关键路径 C语言实现

#include <stdio.h>
#include <stdlib.h>
#define MaxVertexNum 50
#define false 0
#define true 1
typedef int bool;
typedef int Vertex;
typedef int WeightType;
struct VertexNode;//顶点结构
struct AdjNode;//邻接顶点结构
typedef struct AdjNode *PtrToAdjVertexNode;//指向邻接点的指针
typedef struct GraphNode *PtrToGraphNode;//指向图的指针
typedef PtrToGraphNode ListGraph;
typedef struct EdgeNode *Edge;
typedef struct VertexNode
{
    PtrToAdjVertexNode Head;//指向第一个邻接点的指针
} AdjList[MaxVertexNum];
struct AdjNode
{
    Vertex AdjVertex;//邻接点下标
    WeightType Weight;//权重
    PtrToAdjVertexNode Next;
};
struct GraphNode
{
    int VertexNum;
    int EdgeNum;
    AdjList G;
};
/*将边的信息封装,V1到V2权重为Weight的边*/
struct EdgeNode
{
    Vertex V1;
    Vertex V2;
    WeightType Weight;
};
/*Stack ADT*/
typedef Vertex ElementType;
typedef struct StackNode *Stack;
struct StackNode
{
    ElementType *Array;
    int Capacity;
    int Top;
};
int IsEmptyStack(Stack S);
int IsFullStack(Stack S);
Stack CreatStack(int Capacity);
int Push(ElementType X, Stack S);
ElementType Pop(Stack S);
/*Stack END*/
ListGraph CreatGraph(int VertexNum);
void InsertEdge(ListGraph Graph, Edge E);
Edge ReadEdge(void);//输入函数
int* GetInDegree(ListGraph Graph);
int TopologicalOrder(ListGraph Graph, Stack T, int *VertexEarlyTime);//用于关键路径的拓扑排序,传入最早开工时间
int main()
{
    int VertexNum;
    Edge E = NULL;
    printf("输入顶点数:\n");
    scanf("%d",&VertexNum);
    ListGraph Graph = CreatGraph(VertexNum);
    printf("输入边(-1结束),格式:顶点1 顶点2 边权重\n");
    /*

     9个顶点测试数据

1 2 6

1 3 4
1 4 5
2 5 1
3 5 1
4 6 2
5 7 9
5 8 7
6 8 4
7 9 2
8 9 4
-1
     */
    while((E = ReadEdge()) != NULL)
    {
        InsertEdge(Graph,E);
    }
    CriticalPath(Graph);
    return 0;
}
ListGraph CreatGraph(int VertexNum)
{
    Vertex V;
    ListGraph Graph;
    Graph = (ListGraph)malloc(sizeof(struct GraphNode));
    Graph->VertexNum = VertexNum;
    Graph->EdgeNum = 0;
    for (V = 0; V < Graph->VertexNum; V++) {
        Graph->G[V].Head = NULL;
    }
    return Graph;
}
void InsertEdge(ListGraph Graph, Edge E)
{
    PtrToAdjVertexNode NewNode;
    NewNode = (PtrToAdjVertexNode)malloc(sizeof(struct AdjNode));
    NewNode->AdjVertex = E->V2;
    NewNode->Weight = E->Weight;
    /*将新添加的邻接点插在邻接表头*/
    NewNode->Next = Graph->G[E->V1].Head;
    Graph->G[E->V1].Head = NewNode;
}
Edge ReadEdge(void)
{
    Edge E = (Edge)malloc(sizeof(struct EdgeNode));
    scanf("%d",&E->V1);
    if (E->V1 != -1)
    {
        scanf("%d %d",&E->V2,&E->Weight);
    }else
    {
        E = NULL;
    }
    return E;
}
int* GetInDegree(ListGraph Graph)
{
    int i = 0;
    PtrToAdjVertexNode TempHead;
    int *Array = malloc(sizeof(int)*(Graph->VertexNum+1));
    for (i=1; i<=Graph->VertexNum; i++) {
        Array[i] = 0;
    }
    for (i=1; i<=Graph->VertexNum; i++) {
        TempHead = Graph->G[i].Head;
        while (TempHead) {
            Array[TempHead->AdjVertex]++;
            TempHead = TempHead->Next;
        }
    }
    return Array;
}
int TopologicalOrder(ListGraph Graph, Stack T, int *VertexEarlyTime)
{
    int *InDegreeArray = GetInDegree(Graph);
    Stack S = CreatStack(Graph->VertexNum);
    Vertex i,j,k;
    int count = 0;
    PtrToAdjVertexNode P = NULL;
    //建零入度栈
    for (i = 1; i<=Graph->VertexNum; i++) {
        if (InDegreeArray[i] == 0) {
            Push(i, S);
        }
    }
    while (!IsEmptyStack(S)) {
        j = Pop(S);
        Push(j, T);
        count++;
        for (P = Graph->G[j].Head; P; P = P->Next) {
            k = P->AdjVertex;
            InDegreeArray[k]--;
            if (InDegreeArray[k] == 0) {
                Push(k, S);
            }
            if (VertexEarlyTime[j] + P->Weight > VertexEarlyTime[k]) {
                VertexEarlyTime[k] = VertexEarlyTime[j] + P->Weight;
            }
        }
    }
    printf("拓扑排序结果:\n");
    if (IsEmptyStack(T))
    {
        printf("Empty! Top = %d\n",T->Top);
    }
    for (i = 0; i <= T->Top; ++i)
    {
        printf("%d ", T->Array[i]);
    }
    printf("\n");
    if (count < Graph->VertexNum) {
        return false;
    }else
    {
        return true;
    }
}
int CriticalPath(ListGraph Graph)
{
    Vertex i,j,k;
    PtrToAdjVertexNode P;
    Stack T = CreatStack(Graph->VertexNum);
    int *VertexEarlyTime = malloc(sizeof(WeightType)*(Graph->VertexNum+1));
    int *VertexLastTime = malloc(sizeof(WeightType)*(Graph->VertexNum+1));
    char TAG;
    for (i=1; i<=Graph->VertexNum; i++) {
        VertexEarlyTime[i] = 0;
    }
    if (!TopologicalOrder(Graph, T ,VertexEarlyTime)) {
        return false;
    }
    for (i=1; i<=Graph->VertexNum; i++) {
        VertexLastTime[i] = VertexEarlyTime[i];
    }
    while (!IsEmptyStack(T)) {
        for (j = Pop(T),P = Graph->G[j].Head; P; P = P->Next) {
            k = P->AdjVertex;
            if (VertexLastTime[k]- (P->Weight) < VertexLastTime[j]) {
                VertexLastTime[j] = VertexLastTime[k] - (P->Weight);
            }
        }
    }
    printf("关键活动: \n");
    for (j = 0; j<=Graph->VertexNum; j++) {
        for (P = Graph->G[j].Head; P; P = P->Next) {
            k = P->AdjVertex;
            TAG = (VertexEarlyTime[j] == VertexLastTime[k]-P->Weight) ? '*' : ' ';
            printf("%d %d %d %d %d %c\n",j, k, P->Weight, VertexEarlyTime[j],VertexLastTime[k]-P->Weight, TAG);
        }
    }
    return true;
}
/*Stack*/
int IsEmptyStack(Stack S)
{
    return S->Top == -1;
}
int IsFullStack(Stack S)
{
    return S->Top == S->Capacity-1;
}
Stack CreatStack(int Capacity)
{
    Stack S = malloc(sizeof(struct StackNode));
    S->Array = malloc(sizeof(ElementType)*Capacity);
    S->Capacity = Capacity;
    S->Top = -1;
    return S;
}
int Push(ElementType X, Stack S)
{
    if (IsFullStack(S)) {
        return false;
    }
    S->Top++;
    S->Array[S->Top] = X;
    return true;
}
ElementType Pop(Stack S)
{
    if (IsEmptyStack(S)) {
        return false;
    }
    return S->Array[S->Top--];
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值