2.计算工程完成的关键路径

说明:

        AOE 网络是有向无环加权图,其中顶点表示事件,弧表示活动,权表示活动持续的时间,通常可以用来估算工程完成的时间,即图中从开始点到结束点之间最长的路径对应的时间。请完成一个程序,完成下列任务:

        1 、计算 AOE 网络对应的拓扑排序。如果排序结果不唯一,请输出按照从小到大的顺序排列的结果。从小到大的顺序就是输入的节点序列顺序(参见下面关于输入格式的说明)。如图1中满足要求的拓扑排序是: a-b-c-d-e-f-g-h-k ,图2中满足要求的拓扑排序是:v1-v3-v5-v2-v6-v4-v7-v8-v9

        2 、计算 AOE 网络的关键路径。注意关键路径可能不唯一,要求输出所有的关键路径。同样,按照是按照从小到大的顺序输出。例,如果得到两条关键路径,分别是0-1-3-6-8-9和0-1-3-4-5-8-9,那么先输出后一条路径,因为两条路径中前三个节点相同,而后一条路径第四个节点的编号小。

        测试用例的输入输出格式说明:

        输入:

        节点的个数,边的条数;

        各个节点的名称序列

        边: < 起点 , 终点 , 权值 > 。说明起点和终点是在各个点在输入序列中的位置,如图1中边 表示为 <0,1,6> 。

        输出:

        拓扑排序;

        关键路径

 2.计算工程完成的关键路径_第1张图片

2.计算工程完成的关键路径_第2张图片

        测试用例1是与图1相对应的,测试用例2是与图2相对应的。

测试输入 期待的输出 时间限制 内存限制 额外进程
测试用例 1 以文本方式显示
  1. 9,11↵
  2. a,b,c,d,e,f,g,h,k↵
  3. <0,1,6>,<0,2,4>,<0,3,5>,<1,4,1>,<2,4,1>,<4,6,8>,<4,7,7>,<3,5,2>,<5,7,4>,<6,8,2>,<7,8,4>↵
以文本方式显示
  1. a-b-c-d-e-f-g-h-k↵
  2. a-b-e-h-k↵
1秒 64M 0
测试用例 2 以文本方式显示
  1. 9,11↵
  2. v1,v2,v3,v4,v5,v6,v7,v8,v9↵
  3. <0,4,6>,<0,2,4>,<0,5,5>,<4,1,1>,<2,1,1>,<1,6,8>,<1,7,7>,<5,3,2>,<3,7,4>,<6,8,2>,<7,8,4>↵
以文本方式显示
  1. v1-v3-v5-v2-v6-v4-v7-v8-v9↵
  2. v1-v5-v2-v8-v9↵
1秒 64M 0
测试用例 3 以文本方式显示
  1. 4,4↵
  2. A,B,C,D↵
  3. <0,1,2>,<1,3,3>,<3,2,5>,<2,1,1>↵
以文本方式显示
  1. NO TOPOLOGICAL PATH↵
1秒 64M 0

 前置知识简述:

1. 出度与入度

        对有向图,每个顶点被指向的箭头个数,就是它的入度,从这个顶点指出去的箭头个数,就是它的出度。一个顶点的入度与出度之和称为该顶点的度。

2.出度入度的计算

        邻接矩阵:按列遍历矩阵,累计每列1的个数,就是第j个顶点的入度。按层遍历矩阵,累计每行1的个数,就是第i个顶点的出度(i,j均从0开始)【邻接矩阵好做一点,但是用例可能是稀疏矩阵】

        邻接表:计算出度时,遍历所求节点后的结点,不为0的时候,count++,然后指针后移,直到尾部(也可通过边算)。计算入度时,外循环遍历每个顶点,内循环检测该节点边是否连有所求节点,若有则sum++。

3.拓扑排序

        将入度为0的点弹出,并更新还在其后各点的入度,重复操作。(由于入度为0的点不唯一,拓扑排序结果不唯一,)

        本题要求由小到大顺序排列,可将编号存入数组,按照下标读取“大小”。

4.关键路径

        最长权重的路径就是关键路径,在实际意义上等同于完成一件事的最短必需时间的方案。

题目分析

        顶点表示事件,边表示活动,通过顶点算边。

        通过拓扑排序求出事件最早发生时间,反向推导求出事件最晚发生时间,通过事件最早发生时间求出活动最早发生时间,活动最早发生时间等于 from(箭头开始方向的事件最早发生时间),通过活动最早发生时间求出活动最晚发生时间,活动最晚发生时间等于 to - weight(箭头结束方向的事件发生时间 - 权重),通过(活动最晚发生时间-活动最早发生时间)求出关键路径。

代码如下:

        (发现了一个算法可以算关键路径还不用建邻接表,嘿嘿,再配合正则表达式来读取,嘶,完美)

        出题人NM!为什么不好好的按逻辑出题,我就想用邻接矩阵偷个懒,一开始以为是先对同层级的(入度同时为零)排序一下,结果一看第二个用例v2在v6前面,真ex人啊,不过这也还好,算我自己的问题吧。

        但是这乐学编译器怎么还不升级,都不支持regex,服了,给我一直RE,结果一搜是编译器版本的问题,我都忘了乐学只有gcc4.8,服了,输入格式ex人,不想写了,扒代码去了。

        贴个源码(我的偷懒版代码,不想改了,就这样吧)

(过不了用例,只能在自己电脑上跑,乐学***,还有就是输出的排序结果顺序和要求不太一样(第二个用例,感觉都不算是宽度优先了))

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

const int M = 5e4 + 5;
struct Edges
{
    int in;
    int out;
    int weight;
} edge[M];
struct Output
{
    string s;
} output[M];
int node[M], distant[M], degree_in[M];
int sourcepoint;
vector> graph;
vector ans;
vector in;
void topo_sort(int point_number, int sourcepoint)
{
    for (int i = 0; i < point_number; i++)
        for (auto j : graph[i])
            in[j]++;
    queue q;
    q.push(sourcepoint);
    ans.push_back(sourcepoint);
    while (!q.empty())
    {
        int temp = q.front();
        q.pop();
        vector pre;
        for (auto i : graph[temp]){
            in[i]--;
            if (in[i] == 0){
                q.push(i);
                pre.push_back(i);
            }
        }
        sort(pre.begin(), pre.end());
        ans.insert(ans.end(), pre.begin(), pre.end());
        pre.clear();
    }
}
void bellman(int point_number, int edge_number)
{
    memset(node, 0, sizeof(node));
    memset(distant, 0, sizeof(distant));
    for (int k = 1; k < point_number; k++){
        int flag = 0;
        for (int i = 1; i <= edge_number; i++){
            if ((distant[edge[i].in] < distant[edge[i].out] + edge[i].weight) || ((distant[edge[i].in] == distant[edge[i].out] + edge[i].weight) && (edge[i].out < node[edge[i].in]))){
                distant[edge[i].in] = distant[edge[i].out] + edge[i].weight;
                node[edge[i].in] = edge[i].out;
                flag = 1;
            }
        }
        if (flag == 0)
            break;
    }
    while (sourcepoint != 0){
		cout<)");
    smatch match;
    vector a, b, c;
    string::const_iterator searchStart(input.cbegin());
    while (regex_search(searchStart, input.cend(), match, parrten)){
        a.push_back(stoi(match[1]));
        b.push_back(stoi(match[2]));
        c.push_back(stoi(match[3]));
        searchStart = match.suffix().first;
    }
    for (int i = 1; i <= edge_number; i++){
        edge[i].in = a[i - 1]+1;
        edge[i].out = b[i - 1]+1;
        edge[i].weight = c[i - 1];
        degree_in[b[i - 1]+1]++;
        graph[a[i - 1]+1].push_back(b[i - 1]+1);
    }
    for (int i = 1; i <= point_number; i++)
        if (degree_in[i] == 0)
            sourcepoint = i;
    topo_sort(point_number, sourcepoint);
    if (ans.size() == point_number){
        for (auto i : ans){
            cout << output[i - 1].s;
            if (i != ans[ans.size() - 1])
                cout << "-";
        }
        cout << endl;
        bellman(point_number, edge_number);
    }
    else
        cout << "NO TOPOLOGICAL PATH" << endl;
    return 0;
}

        找代码去咯!(附个链接)

        计算工程完成的关键路径(C++语言)-CSDN博客

你可能感兴趣的:(c++,算法)