求AOE网的关键路径

以边表示活动,以顶点表示事件的有向网称为AOE(activity on edge)网.AOE网是一个
有向无环图,权值表示活动持续的时间。可以用AOE网来估计工程完成的时间。由于工程
只有一个开始点和一个完成点,所以在无环路的条件下,网中只有一个入度为0的点和一
个出度为0的点.
下面是几个和AOE网有关的概念:
(1)路径长度:路径上各个活动的持续时间之和

(2)完成工程的最短时间:由于AOE网中有活动是并行进行的,所以完成工程的最短时间
就是从开始点到完成点的最长路劲长度。
(3)活动最早开始时间(earlist time)(e(i)):从开始点到顶点vi的最长路径称为事件vi的最早发生时间,

这个时间决定了以vi为尾的弧表示的活动的最早开始时间.
(4)活动最晚开始时间(latest time)(l(i)):在不推迟整个工程完成的前提下,活动最迟开始的时间
(5)完成活动的时间余量:该活动的最迟开始时间减去最早开始时间
(6)关键路径(critical path):路径长度最长的路径称为关键路径
(7)关键活动(critical activity):关键路径上的活动称为关键活动,关键活动的特点是:e(i)=l(i)
分析关键路径的目的就是辨别在整个工程中哪些是关键活动,以便争取提高关键活动的工作
效率,缩短整个工程的工期。

文件"aoe.h"

#include<iostream> #include<string> #include<stack> #include<iomanip> using namespace std; const int MAX_VEX_NUM=20; int ve[20];//全局变量,存放各个事件的最早发生时间 class ArcNode //表结点 { public: int adjvex; int info;//权值 ArcNode *nextarc; }; class VNode //头结点 { public: string data; int indegree; //顶点的入度 ArcNode *firstarc; }; class ALGraph { private: VNode vertices[MAX_VEX_NUM]; int arcnum; int vexnum; public: void Create_ALG() { //构造有向网 string v1,v2; int i,j,w; ArcNode *p=NULL; cout<<"输入顶点数和边数:"; cin>>vexnum>>arcnum; cout<<"输入顶点名称:"; for(i=0;i<vexnum;i++) { cin>>vertices[i].data; vertices[i].firstarc=NULL; vertices[i].indegree=0; } for(int k=0;k<arcnum;k++) { cout<<"按照尾->头的顺序输入每条边对应的两个顶点和该边的权值:"; cin>>v1>>v2>>w; i=Locate_Vex(v1); j=Locate_Vex(v2); while(i==-1 || j==-1) { cout<<"输入的顶点错误,重新输入:"; cin>>v1>>v2; i=Locate_Vex(v1); j=Locate_Vex(v2); } p=new ArcNode; p->adjvex=j; p->info=w; p->nextarc=vertices[i].firstarc; vertices[i].firstarc=p; vertices[j].indegree+=1; //作为有向弧的头的顶点入度加1 } cout<<"有向网构造完成"<<endl; } int Locate_Vex(string v) //求顶点在顶点数组中的位置 { for(int k=0;k<vexnum && vertices[k].data!=v;k++); if(k<vexnum) return k; else return -1; } /*关键路径求解思想*/ /*--------------------------------------------------------------- / 辨别关键路径就是要找出l(i)=e(i)的活动,为了求AOE网中的e(i)和l(i) / 首先应该求出每个事件的最早发生时间ve(j)和最晚发生时间vl(j),如果 / 活动ai用弧<j,k>表示,那么持续时间记为dut(<j,k>).则有如下关系: / e(i)=ve(j), l(i)=vl(k)-dut(<j,k>); / 求事件的vj的最早发生时间ve(j)和最迟发生时间vl(j)要分两步进行: / (1):从ve(0)=0(假设顶点0是开始点)开始,根据下面公式计算其它事件 / 的最早开始时间: ve(j)=Max{ve(i)+dut(<i,j>)} 其中i是j的所有直接前驱的集合 / (2)从vl(n-1)=ve(n-1)开始,根据下面公式计算其他事件的最晚开始时间: / vl(i)=Min{vl(j)-dut(<i,j>)} 其中j是i的直接后继的集合 / 上述两个公式必须分别在拓扑有序和逆拓扑有序的前提下进行,也就是说ve(j-1) / 必须在vj全部直接前驱的最早发生时间都求得以后才能确定。而vl(j-1)则必须在 / vj的所有直接后继的最晚发生时间求得之后才能确定,因此可以在拓扑排序的基础 / 上计算所有事件的ve(j-1)和vl(j-1). / 为了能按逆拓扑有序序列的顺序计算各个顶点的vl值,需记下在拓扑排序的过程中 / 求得的拓扑有序序列,这只需要增加多一个栈,用来存储拓扑有序序列即可. / 由于栈的结构特点,拓扑有序序列出栈就变成逆拓扑有序序列了. /----------------------------------------------------------------*/ //求所有事件的最早发生时间 bool Topo_Order(stack<int> &T) { stack<int> s; ArcNode *p=NULL; for(int i=0;i<vexnum;i++) if(!vertices[i].indegree) s.push(i); int count=0; for(i=0;i<vexnum;i++) ve[i]=0; //设各顶点最早发生为0 while(!s.empty()) { int k=s.top(); s.pop(); T.push(k); count++; for(p=vertices[k].firstarc;p;p=p->nextarc) { int w=p->adjvex; if(vertices[w].indegree) vertices[w].indegree--; if(!vertices[w].indegree) s.push(w); if(ve[k]+p->info>ve[w]) //求ve[w]的最早发生时间 ve[w]=ve[k]+p->info; } } if(count<vexnum) return 0; else return 1; } //求所有事件的最晚发生时间并求出关键活动和关键路径 void Critical_Path() { stack<int> T; string cp[10]; int c=0; if(!Topo_Order(T)) { cout<<"该有向网有环!"<<endl; return; } int vl[20]; for(int i=0;i<vexnum;i++) vl[i]=ve[vexnum-1]; //初始化顶点事件最迟发生时间 while(!T.empty()) { ArcNode *p=NULL; int j=T.top(); T.pop(); for(p=vertices[j].firstarc;p;p=p->nextarc) { int k=p->adjvex; int dut=p->info; if(vl[k]-dut<vl[j]) vl[j]=vl[k]-dut; } } //下面是根据关键活动的特点(最早开始时间和最晚开始时间相等)求关键活动,做上标记 cout<<"tail head weight earliest time latest time tag "<<endl; for(int j=0;j<vexnum;j++) for(ArcNode *p=vertices[j].firstarc;p;p=p->nextarc) { int k=p->adjvex; int dut=p->info; int ee=ve[j]; int el=vl[k]-dut; char tag; tag=(ee==el)?'*':' '; cout<<setw(3)<<vertices[j].data<<setw(6)<<vertices[k].data<<setw(7)<<dut<<setw(9)<<ee<<setw(16)<<el<<setw(9)<<tag<<endl; if(tag=='*' && j==0) { cp[c]=vertices[j].data; c++; cp[c]=vertices[k].data; c++; } else if(tag=='*' && j!=0) { cp[c]=vertices[k].data; c++; } } cout<<"The critical activities are ended with * "<<endl; cout<<"So the critical path is :"; for(i=0;i<c-1;i++) cout<<cp[i]<<"->"; cout<<cp[c-1]<<endl; } };

主函数"main.cpp"

#include"aoe.h" int main() { ALGraph G; G.Create_ALG(); G.Critical_Path(); cout<<endl; return 0; }

输入和输出结果:

输入顶点数和边数:6 8 输入顶点名称:v1 v2 v3 v4 v5 v6 按照尾->头的顺序输入每条边对应的两个顶点和该边的权值:v1 v2 3 按照尾->头的顺序输入每条边对应的两个顶点和该边的权值:v1 v3 2 按照尾->头的顺序输入每条边对应的两个顶点和该边的权值:v2 v5 3 按照尾->头的顺序输入每条边对应的两个顶点和该边的权值:v2 v4 2 按照尾->头的顺序输入每条边对应的两个顶点和该边的权值:v3 v4 4 按照尾->头的顺序输入每条边对应的两个顶点和该边的权值:v3 v6 3 按照尾->头的顺序输入每条边对应的两个顶点和该边的权值:v4 v6 2 按照尾->头的顺序输入每条边对应的两个顶点和该边的权值:v5 v6 1 有向网构造完成 tail head weight earliest time latest time tag v1 v3 2 0 0 * v1 v2 3 0 1 v2 v4 2 3 4 v2 v5 3 3 4 v3 v6 3 2 5 v3 v4 4 2 2 * v4 v6 2 6 6 * v5 v6 1 6 7 The critical activities are ended with * So the critical path is :v1->v3->v4->v6 Press any key to continue

根据输入所生成的有向网如下所示:

当关键路径只有一条时,输出关键路径是对的,当关键路径不知一条时就是错的,但是依然是可以找出所有的关键活动,路径输出的算法,以后会完善到可以输出所以关键路径

求逆拓扑有序序列 除了利用求拓扑有序时进栈外,还可以直接用DFS遍历该有向图,直到该结点的所有邻接结点都输出之后,才将其输出,这个序列就是逆拓扑有序序列

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值