活动网络——AOE网络

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

AOE网络的用途

(1)完成整个工程至少需要多长时间

 (2)为缩短工程所需的时间,应加快哪些活动


关键路径:完成整个工程所需的时间取决于从源点到汇点的最长路径长度,这条路径最长的路径就称为关键路径。(Critical Path);

常用的量:(1)事件Ei的最早可能开始时间,记为Ee[i].是从源点到顶点Ei的最长路径长度

                   (2)事件Ei的最迟可能开始时间,记为El[i].El[i]是在保证汇点En-1在Ee[n-1]时刻完成的前提下,事件Ei允许开始的最迟时间,它等于Ee[n-1]减去从Ei到En-1的最长路径长度。

                    (3)活动ak的最早可能开始时间,记为e[k]。设活动在有向边<Ei,Ej>上,e[k]=Ee[i].

                     (4)活动ak最迟允许开始的时间,记为l[l].   l[k]=El[j]-dur<Ei,Ej>的值。

松弛时间:l[k]-e[k]

求Ee[i]的递推公式,从Ee[0]=0开始,向前递推:

Ee[i]=max{Ee[j]+dur(<Ej,Ei>)}.

求El[i]的递推公式。从El[n-1]=Ee[n-1]开始,反向递推

El[i]=min{  El[j]-dur(<Ei,Ej>)  }.

这两个递推公式必须在拓扑有序及逆拓扑有序的前提下进行。所谓逆拓扑有序,就是首先输出出度为0的顶点,以相反的次序输出拓扑排序序列,这种排序称为逆拓扑排序。

也就是说,在计算Ee[i]时,Ei的所有前驱顶点Ej的Ee[j]都已经求出。反之,在计算El[i]时,Ei的所有后继顶点El[j]都已经求出

例题:求如图所示的AOE网络的关键路径并输出。首先输入顶点个数n和边个数m,然后依次输入每条边



#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define MAXN 100///顶点数目的最大值
#define MAXM 200///边的数目的最大值
struct ArcNode
{
    int to,dur,no;///no为活动序号
    ArcNode *next;
};
int n,m;
ArcNode *list1[MAXN];///出边表的表头指针
ArcNode *list2[MAXN];///入边表的表头指针
int count1[MAXN];///各顶点的入度
int count2[MAXN];///各顶点的出度
int Ee[MAXN];///各事件最早可能开始的时间
int El[MAXN];///各事件允许开始的最迟时间
int e[MAXM];///各活动最早可能开始的时间
int l[MAXM];///各活动允许最晚可以开始的时间
void CriticalPath();
int main()
{
    int i,j;
    int u,v,w;
     while(scanf("%d%d",&n,&m)!=EOF)///顶点数和边数
    {
        if(n==0&&m==0) break;
       memset(list1,0,sizeof(list1));
       memset(list2,0,sizeof(list2));
       memset(count1,0,sizeof(count1));
       memset(count2,0,sizeof(count2));
       ArcNode *temp1,*temp2;
       for(i=0;i<m;i++)
       {
           scanf("%d%d%d",&u,&v,&w);
           count1[v]++;
           temp1=new ArcNode;///构造邻接表
           temp1->to=v;
           temp1->dur=w;
           temp1->no=i+1;
           temp1->next=NULL;
           if(list1[u]==NULL)
            list1[u]=temp1;
           else
           {
               temp1->next=list1[u];
               list1[u]=temp1;
           }
           count2[u]++;
           temp2=new ArcNode;///构造逆邻接表
           temp2->to=u;
           temp2->dur=w;
           temp2->no=i+1;
           temp2->next=NULL;
           if(list2[v]==NULL)
            list2[v]=temp2;
           else
           {
               temp2->next=list2[v];
               list2[v]=temp2;
           }
       }
       CriticalPath();
       ///释放边链表上各边结点所占用的空间
       for(i=0;i<n;i++)
       {
           temp1=list1[i];
           temp2=list2[i];
           while(temp1!=NULL)
           {
               list1[i]=temp1->next;
               delete temp1;
               temp1=list1[i];
           }
           while(temp2!=NULL)
           {
               list2[i]=temp2->next;
               delete temp2;
               temp2=list2[i];
           }
       }

    }
    return 0;
}
void CriticalPath()
{
    ///拓扑排序求Ee;
     int i,j,k;
     int top1=-1;
     ArcNode *temp1;
     memset(Ee,0,sizeof(Ee));
     for(i=0;i<n;i++)///找出入度为0的点
     {
         if(count1[i]==0)
         {
             count1[i]=top1;
             top1=i;
         }
     }
     for(i=0;i<n;i++)
     {
         if(top1==-1)
         {
             printf("Network has a cycle\n");
             return ;
         }
         else
            {
               j=top1;
              top1=count1[top1];
              temp1=list1[j];
           while(temp1!=NULL)
           {
               k=temp1->to;
               count1[k]--;
               if(count1[k]==0)
               {
                   count1[k]=top1;
                   top1=k;
               }
               if(Ee[j]+temp1->dur>Ee[k])
                Ee[k]=Ee[j]+temp1->dur;
               temp1=temp1->next;
           }
        }
     }
     ///逆拓扑排序求El;
     int top2=-1;
     ArcNode *temp2;
     for(i=0;i<n;i++)///找出出度为0的顶点
     {
         El[i]=Ee[n-1];///初始化为已知的最大值
         if(count2[i]==0)
         {
             count2[i]=top2;
             top2=i;
         }
     }
     for(i=0;i<n;i++)
     {
         j=top2;
         top2=count2[top2];
         temp2=list2[j];
         while(temp2!=NULL)
         {
             k=temp2->to;
             count2[k]--;
             if(count2[k]==0)
             {
                 count2[k]=top2;
                 top2=k;
             }
             if(El[j]-temp2->dur<El[k])
                El[k]=El[j]-temp2->dur;
             temp2=temp2->next;
         }
     }
      ///输出Ee[i]和El[i]
     for(i=0;i<n;i++)
        cout<<Ee[i]<<" ";
     cout<<endl;
     for(i=0;i<n;i++)
        cout<<El[i]<<" ";
        cout<<endl;
     ///求各种活动的e[k]和l[k];
     memset(e,0,sizeof(e));
     memset(l,0,sizeof(l));
     printf("the critical activities:\n");
     for(i=0;i<n;i++)
     {
         temp1=list1[i];
         while(temp1!=NULL)
         {
             j=temp1->to;///有向边<i,j>;
             k=temp1->no;
             e[k]=Ee[i];
             l[k]=El[j]-temp1->dur;
              if(e[k]==l[k])
                {
                     printf("a%d : %d->%d\n",k,i,j);
                }
             temp1=temp1->next;
         }
     }
     ///输出e[i]和l[i]的值
      for(i=0;i<m;i++)
        cout<<e[i]<<" ";///为啥前四个都为0??因为是最早可能开始的时间
     cout<<endl;
     for(i=0;i<m;i++)
        cout<<l[i]<<" ";
     cout<<endl;
}
测试数据:


TMD书上的测试数据竟然给错,还好有超哥相助,多谢超哥


  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AOE网中,求关键路径的步骤如下: 1. 首先,需要计算每个活动的最早开始时间ve(i)。从源点开始,逐个计算每个活动的最早开始时间,直到汇点。ve(i)的计算公式为:ve(i) = max{ve(j) + d(j,i)},其中j为活动i的前驱活动,d(j,i)为活动j到活动i的持续时间。 2. 接下来,需要计算每个活动的最迟开始时间vl(i)。从汇点开始,逐个计算每个活动的最迟开始时间,直到源点。vl(i)的计算公式为:vl(i) = min{vl(j) - d(i,j)},其中j为活动i的后继活动,d(i,j)为活动i到活动j的持续时间。 3. 然后,计算每个活动的最早完成时间e(i)。e(i)的计算公式为:e(i) = ve(i)。 4. 接着,计算每个活动的最迟完成时间l(i)。l(i)的计算公式为:l(i) = vl(i) - d(i),其中d(i)为活动i的持续时间。 5. 最后,计算每个活动的总浮动时间l(i) - e(i)。如果某个活动的总浮动时间为0,则该活动为关键活动。关键活动所在的路径即为关键路径。 需要注意的是,只有减少关键活动的时间才可能缩短工期,而且只有在不改变关键路径的前提下减少关键活动的时间才可能缩短工期。 #### 引用[.reference_title] - *1* [(数据结构)AOE网求关键路径](https://blog.csdn.net/weixin_51609435/article/details/123817811)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [图的关键路径(AOE网络)](https://blog.csdn.net/m0_61433144/article/details/128730798)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值