• 数据结构 关键路径


      如果在有向无环图中用有向边表示一个工程中的各项活动(Activity),用有向边上的权值表示活动的持续时间(duration),用顶点表示事件(Event),则这种有向图叫做用边表示活动的网络(activity on edges),简称AOE网络。例如:

      

      其中,Ei表示事件,ak表示活动。E0是源点,E8是汇点。

      完成整个工程所需的时间等于从源点到汇点的最长路径长度,即该路径中所有活动的持续时间之和最大。这条路径称为关键路径(critical path)。关键路径上所有活动都是关键活动。所谓关键活动(critical activity),是不按期完成会影响整个工程进度的活动。只要找到关键活动,就可以找到关键路径。

      与计算关键活动有关的量:

      1 事件Ei的最早可能开始时间:Ee[i]—从源点E0到顶点Ei的最长路径长度。在上图中,Ee[4]=7。

      2 事件Ei的最迟允许开始时间:El(小写L)[i]—在保证汇点En-1最迟允许开始时间El[n-1]等于整个工程所需时间的前提下,等于El[n-1]减去从Ei到En-1的最长路径长度。

      3 活动ak的最早可能开始时间:e[k]—设该活动在有向边<Ei,Ej>上,从源点E0到顶点Ei的最长路径长度,即等于Ee[i]。

      4 活动ak的最迟允许开始时间:l(小写L)[k]—设该活动在有向边<Ei,Ej>上,在不会引起时间延误的前提下,允许的最迟开始时间。l[k]=El[j]-dur(<Ei,Ej>),其中dur(<Ei,Ej>)是完成该活动所需的时间,即有向边<Ei,Ej>的权值。

      l[k]-e[k]表示活动ak最早可能开始时间和最迟允许开始时间的时间余量,也叫做松弛时间(slack time)。没有时间余量的活动是关键活动。

      算法步骤:

      1 输入顶点数和边数,再输入每条边的起点编号、终点编号和权值。根据边的信息,通过一维数组存储每个顶点的入度和出度,建立邻接表保存边。每个顶点的Ee[i]设为0,El[i]设为100000000(表示无限大)。

      2 按拓扑排序遍历所有顶点,更新Ee[i]。如果拓扑排序循环次数小于顶点数n,则说明网络中存在有向环,不能继续求关键路径。更新Ee[i]的最大值(整个工程所需时间)。

      3 把所有汇点的最迟允许开始时间设为整个工程所需时间,按逆拓扑排序遍历所有顶点,更新El[i]。

      4 通过DFS遍历所有边<Ei,Ej>。如果l[k]等于e[k],则说明该活动是关键活动。依次输出关键活动上的顶点后构成关键路径。

      在上图中,关键路径是a1-a4-a7-a10或a1-a4-a8-a11,完成整个工程所需时间是18。

      题目 PTA 数据结构与算法题目集(中文) 7-11 关键活动(30 分)

      多源点和多汇点例子:

     1 11 14
     2 1 2 4
     3 1 3 3
     4 2 4 5
     5 3 4 3
     6 4 5 1
     7 4 6 6
     8 5 7 5
     9 6 7 2
    10 8 3 7
    11 9 3 7
    12 9 10 6
    13 4 10 2
    14 10 6 5
    15 6 11 4

      

      结果如下:

    1 21
    2 3->4
    3 4->10
    4 6->11
    5 8->3
    6 9->3
    7 10->6

      C++代码如下:

      1 //#include "stdafx.h"
      2 #include <iostream>
      3 #include <vector>
      4 #include <queue>
      5 
      6 using namespace std;
      7 
      8 struct node
      9 {
     10     int next, time;
     11 };
     12 
     13 int degree[2][110], t[2][110], maxtime;
     14 vector<node> v[2][110];
     15 
     16 int torder(int index, int n)
     17 {
     18     int i;
     19     queue<int> q;
     20 
     21     for(i = 1; i <= n; i++)
     22     {
     23         if(degree[index][i] == 0)
     24         {
     25             if(index == 1)
     26             {
     27                 t[1][i] = maxtime;
     28             }
     29 
     30             q.push(i);
     31         }
     32     }
     33 
     34     int cur, size, next, nexttime[2], curtime, count = 0;
     35     while(q.size() > 0)
     36     {
     37         cur = q.front();
     38         q.pop();
     39 
     40         count++;
     41 
     42         size = v[index][cur].size();
     43         for(i = 0; i < size; i++)
     44         {
     45             next = v[index][cur][i].next;
     46             degree[index][next]--;
     47 
     48             if(degree[index][next] == 0)
     49             {
     50                 q.push(next);
     51             }
     52 
     53             curtime = t[index][cur];
     54             nexttime[0] = curtime + v[index][cur][i].time;
     55             nexttime[1] = curtime - v[index][cur][i].time;
     56 
     57             if(index == 0 && nexttime[0] > t[0][next])
     58             {
     59                 t[0][next] = nexttime[0];
     60             }
     61             else if(index == 1 && nexttime[1] < t[1][next])
     62             {
     63                 t[1][next] = nexttime[1];
     64             }
     65         }
     66 
     67         if(index == 0 && t[0][cur] > maxtime)
     68         {
     69             maxtime = t[0][cur];
     70         }
     71     }
     72 
     73     if(count < n)
     74     {
     75         return 0;
     76     }
     77 
     78     return 1;
     79 }
     80 
     81 int main()
     82 {
     83     int n, m;
     84     scanf("%d%d", &n, &m);
     85 
     86     int i, a, b;
     87     node nod;
     88 
     89     for(i = 1; i <= m; i++)
     90     {
     91         scanf("%d%d%d", &a, &b, &nod.time);
     92 
     93         nod.next = b;
     94         v[0][a].push_back(nod);
     95 
     96         nod.next = a;
     97         v[1][b].push_back(nod);
     98 
     99         degree[1][a]++;
    100         degree[0][b]++;
    101     }
    102 
    103     for(i = 1; i <= n; i++)
    104     {
    105         t[0][i] = 0;
    106         t[1][i] = 100000000;
    107     }
    108 
    109     for(i = 0; i <= 1; i++)
    110     {
    111         if(torder(i, n) == 0)
    112         {
    113             printf("0
    ");
    114             return 0;
    115         }
    116     }
    117 
    118     printf("%d
    ", maxtime);
    119 
    120     int size, j, next;
    121     for(i = 1; i <= n; i++)
    122     {
    123         size = v[0][i].size();
    124         for(j = size - 1; j >= 0; j--)
    125         {
    126             next = v[0][i][j].next;
    127             if(t[1][next] - t[0][i] == v[0][i][j].time)
    128             {
    129                 printf("%d->%d
    ", i, next);
    130             }
    131         }
    132     }
    133 
    134     system("pause");
    135     return 0;
    136 }
    View Code

      

      参考资料

      《图论算法理论、实现及应用》

      06-图8. 关键活动(30)

  • 相关阅读:
    winform解析json API数据
    c#(winform)获取本地打印机
    winform程序post提交数据API
    C#关于panle重叠
    net面试总结的题目
    委托
    最实用JS 留着学习
    dev 控件获得所有的EFDEVGRID
    c#利用WebClient和WebRequest获取网页源代码的比较
    浅谈.Net WebService开发
  • 原文地址:https://www.cnblogs.com/WJQ2017/p/7625286.html
Copyright © 2020-2023  润新知