问题 A: 关键路径

1 问题

2 解析

2.1 题意

求有向无环图的关键路径和关键路径长度

2.2 思路

  • 1 用拓扑排序求ve,从而得到数组e
  • 2 用逆拓扑排序求vl,从而得到数组l
  • 3 当数组e和数组l相等时,即为关键活动,加入关键路径中
  • 4 关键路径长度为最后一个事件的最迟发生时间

3 参考代码

#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <cstring>
#include <map>

using std::queue;
using std::stack;
using std::vector;
using std::fill;
using std::map;

struct node
{
    int v;
    int w;
    node(int _v, int _w):v(_v), w(_w){}
};

const int MAXN = 20;
vector<node> G[MAXN];//图
int ve[MAXN], vl[MAXN];
int N;
stack<int> topOrder;
int inDegree[MAXN];
map<char, int> letterToIndex;//字母映射数字
vector<int> ans[MAXN];//关键路径
char str[MAXN];//输入的字母串

//拓扑排序
bool topologicalSort(){

    queue<int> q;
    for (int i = 0; i < N; ++i)
    {
        if(inDegree[i] == 0){
            q.push(i);
        }
    }

    while(!q.empty()){
        int u = q.front();
        q.pop();

        topOrder.push(u);
        for (int i = 0; i < G[u].size(); ++i)
        {
            int v = G[u][i].v;
            inDegree[v]--;
            if(inDegree[v] == 0){
                q.push(v);
            }
            if(ve[u] + G[u][i].w > ve[v]){
                ve[v] = ve[u] + G[u][i].w;
            }
        }
    }

    if(topOrder.size() == N) return true;
    else return false;
}


int CriticalPath(){
    memset(ve, 0, sizeof(ve));
    if(topologicalSort() == false){//求ve
        return -1;
    }
    int maxLength = 0;
    for (int i = 0; i < N; ++i)
    {
        if(ve[i] > maxLength){
            maxLength = ve[i];
        }
    }
    fill(vl, vl + MAXN, maxLength);

    while(!topOrder.empty()){//逆拓扑排序,求vl
        int u = topOrder.top();
        topOrder.pop();
        for (int i = 0; i < G[u].size(); ++i)
        {
            int v = G[u][i].v;
            if(vl[v] - G[u][i].w < vl[u]){
                vl[u] = vl[v] - G[u][i].w;
            }
        }
    }

    for (int i = 0; i < N; ++i)//清空上一次关键路径
    {
        ans[i].clear();
    }

    for (int u = 0; u < N; ++u)
    {
        for (int i = 0; i < G[u].size(); ++i)
        {
            int v = G[u][i].v, w = G[u][i].w;
            int e = ve[u], l = vl[v] - w;
            if(e == l){//是关键活动,则存入关键路径
                ans[u].push_back(v);
            }
        }
    }

    int s;
    for (int i = 0; i < N; ++i)//寻找事件起始点
    {
        if(ve[i] == 0){
            s = i;
            break;
        }
    }

    while(ans[s].size()){//没有后继结点时,退出
        printf("(%c,%c) ", str[s], str[ans[s][0]]);
        s = ans[s][0];
    }
    return ve[N - 1];//return maxLength;
}

int main(int argc, char const *argv[])
{
    int n, m, w;
    char a, b;
    scanf("%d", &n);
    for (int i = 0; i < n; ++i)
    {
        memset(inDegree, 0, sizeof(inDegree));

        scanf("%d%d", &N, &m);
        for (int j = 0; j < N; ++j)
        {
            G[j].clear();
        }

        scanf("%s", str);
        for (int j = 0; j < N; ++j)
        {
            letterToIndex[str[j]] = j;
        }

        for (int j = 0; j < m; ++j)
        {
            //getchar();
            scanf("%*c%c %c %d", &a, &b, &w);
            G[letterToIndex[a]].push_back(node(letterToIndex[b], w));
            inDegree[letterToIndex[b]]++;
        }

        int length = CriticalPath();
        printf("%d\n", length);
    }
    return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁星蓝雨

如果觉得文章不错,可以请喝咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值