活动网络——AOE网络

来源:互联网 发布:淘宝花呗在哪里开通 编辑:程序博客网 时间:2024/06/06 10:04

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书上的测试数据竟然给错,还好有超哥相助,多谢超哥


1 0