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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值