求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
#include
#include
#include
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>vertices[i].data;
			vertices[i].firstarc=NULL;
			vertices[i].indegree=0;
		}

		for(int k=0;k头的顺序输入每条边对应的两个顶点和该边的权值:";
			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<<"有向网构造完成"<表示,那么持续时间记为dut().则有如下关系:
			/ e(i)=ve(j),   l(i)=vl(k)-dut();
			/ 求事件的vj的最早发生时间ve(j)和最迟发生时间vl(j)要分两步进行:
			/ (1):从ve(0)=0(假设顶点0是开始点)开始,根据下面公式计算其它事件
			/ 的最早开始时间: ve(j)=Max{ve(i)+dut()} 其中i是j的所有直接前驱的集合
			/ (2)从vl(n-1)=ve(n-1)开始,根据下面公式计算其他事件的最晚开始时间:
			/ vl(i)=Min{vl(j)-dut()} 其中j是i的直接后继的集合
			/ 上述两个公式必须分别在拓扑有序和逆拓扑有序的前提下进行,也就是说ve(j-1)
			/ 必须在vj全部直接前驱的最早发生时间都求得以后才能确定。而vl(j-1)则必须在
			/ vj的所有直接后继的最晚发生时间求得之后才能确定,因此可以在拓扑排序的基础
			/ 上计算所有事件的ve(j-1)和vl(j-1).
			/ 为了能按逆拓扑有序序列的顺序计算各个顶点的vl值,需记下在拓扑排序的过程中
			/ 求得的拓扑有序序列,这只需要增加多一个栈,用来存储拓扑有序序列即可.
			/ 由于栈的结构特点,拓扑有序序列出栈就变成逆拓扑有序序列了.
			/----------------------------------------------------------------*/

	//求所有事件的最早发生时间
	bool Topo_Order(stack &T)
	{
		stack s;
		ArcNode *p=NULL;
		for(int i=0;inextarc)
			{
				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 T;
		string cp[10];
		int c=0;
		if(!Topo_Order(T))
		{
			cout<<"该有向网有环!"<nextarc)
			{
				int k=p->adjvex;
				int dut=p->info;
				if(vl[k]-dutnextarc)
			{
				int k=p->adjvex;
				int dut=p->info;
				int ee=ve[j];
				int el=vl[k]-dut;
				char tag;
				tag=(ee==el)?'*':' ';
				cout<";
		cout<

主函数"main.cpp"

#include"aoe.h"

int main()
{
	ALGraph G;
	G.Create_ALG();
	G.Critical_Path();
	cout<

输入和输出结果:

输入顶点数和边数: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遍历该有向图,直到该结点的所有邻接结点都输出之后,才将其输出,这个序列就是逆拓扑有序序列

你可能感兴趣的:(Data,Structure)