数据结构-AOE有向网-AOE网的关键路径(拓扑排序)

 注:本文采用拓扑排序和关键路径算法求关键路径权值和

Description

题目内容:对一个工程网,计算完成工程的最短工期。根据输入建立有向带权图,并验证有向无环图,利用拓扑排序,求出关键路径,计算工期。

说明:输入第一行为结点数;第二行为各结点名称;第三行至最后为带权的有向边。

输出为:关键路径的关键活动权值和,即该工程的最短工期。

 

Sample Input

9

A B C D E F G H M

A B 3

A C 10

B D 9

B E 13

C E 12

C F 7

D G 8

D H 4

E H 6

F H 11

G M 2

H M 5

Sample Output

33

Hint

输出有换行符

#include <bits/stdc++.h>
#define Maxnum 1005
#define Maxint 32767
using namespace std;
stack<int> S; // 拓扑排序的顶点栈
stack<int> T; // 入度为0的顶点栈
// 邻接表的存储结构
typedef struct Arcnode
{
    int adjvex; // 邻接点下标
    struct Arcnode *nextarc;
    int info; // 权值
};
typedef struct Vnode
{                 // 邻接链表
    int indu = 0; // 入度
    char data;
    Arcnode *firstarc;
} Vnode, Adjlist[Maxnum];
typedef struct
{
    Adjlist verices;
    int vex, arc;
} ALG;
int locatevex(ALG G, char v)
{ // 查找函数
    int i;
    for (int i = 0; i < G.vex; i++)
    {
        if (v == G.verices[i].data)
        {
            return i;
        }
    }
}
void creatALG(ALG &G)
{ // 有向网的创建
    cin >> G.vex;
    char v1, v2;
    for (int i = 0; i < G.vex; i++)
    {
        cin >> G.verices[i].data;
        G.verices[i].firstarc = NULL;
    }
    int in;
    while (cin >> v1 >> v2 >> in)
    {                             // 输入结点和权值
        int i = locatevex(G, v1); // 查找对应下标
        int j = locatevex(G, v2);
        Arcnode *p = new Arcnode;
        p->adjvex = j;
        G.verices[j].indu++; // 记录每个结点的入度
        p->info = in;
        p->nextarc = G.verices[i].firstarc;
        G.verices[i].firstarc = p;
    }
}
int ve[Maxnum], vl[Maxnum]; // ve最早发生时间 vl最晚发生时间
void Topu(ALG G)
{                                           // 拓扑排序记录顶点栈和最早发生数组ve
    int j, p, k, cnt = 0, indegree[Maxnum]; // indegree为入度数组对应结点下标
    for (int i = 0; i < G.vex; i++)
    { // 初始化
        ve[i] = 0;
        indegree[i] = G.verices[i].indu;
        // cout << indegree[i] << " ";
        if (G.verices[i].indu == 0)
            T.push(i); // 入栈
    }
    while (!T.empty())
    {
        Arcnode *p = new Arcnode;
        j = T.top();
        T.pop();
        S.push(j); // j号顶点入S拓扑排序栈
        cnt++;
        for (p = G.verices[j].firstarc; p; p = p->nextarc)
        {                           // 遍历改点邻接结点
            k = p->adjvex;          // 对应j号结点的邻接点的每个入度减1
            if (--indegree[k] == 0) // 如果入度为0,进栈
                T.push(k);
            if (ve[j] + p->info > ve[k]) // 更新该结点的最早发生时间
                ve[k] = ve[j] + p->info;
        }
    }
}

void Critical(ALG G, int &num)
{ // 关键路径
    int j, k, dut;
    Arcnode *p = new Arcnode;
    for (int i = 0; i < G.vex; i++)
    { // 初始化每个结点的最迟都为结束结点的最早发生时间
        vl[i] = ve[G.vex - 1];
    }
    while (!S.empty())
    { // 按拓扑排序顶点栈求各顶点的vl
        for (j = S.top(), S.pop(), p = G.verices[j].firstarc; p; p = p->nextarc)
        { // 取栈顶并遍历每个邻接点
            k = p->adjvex;
            dut = p->info;
            if (vl[k] - dut < vl[j]) // 更新最晚发生时间vl
                vl[j] = vl[k] - dut;
        }
    }
    int cnt1, cnt2 = 0; // 记录前一段弧的的结点下标
    for (j = 0; j < G.vex; j++)
    { // 求关键路径
        for (p = G.verices[j].firstarc; p; p = p->nextarc)
        {
            k = p->adjvex; // k为邻接点
            dut = p->info; // 权值
            int ee, el;    // ee为每个结点最早发生时间 el为每个结点最晚发生时间
            char tag;
            ee = ve[j];
            el = vl[k] - dut;
            // tag = (ee == el) ? '*' : '#';
            if (ee == el && j != cnt1 && j == cnt2) // 防止有多条关键路径
            {                                       // 最早和最晚相同为关键事件
                num += dut;                         // 权值加和
                cnt1 = j;
                cnt2 = k;
            }
            // cout << j << " " << k << " " << dut << " " << ee << " " << el << " " << tag << "\n";
        }
    }
}

int main()
{
    ALG G;
    int num = 0; // 关键路径权值和
    creatALG(G);
    Topu(G);
    Critical(G, num);
    cout << num << "\n";
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值