AOE网 求关键路径(用邻接表实现)

这篇博客介绍了AOE网(边表示活动的网)的概念,它是一种用于估算工程完成时间的有向无环图。文章详细阐述了AOE网的结构,包括事件、活动和权值的含义,以及关键路径、最早发生时间和最迟开始时间的概念。作者提供了求解关键路径的算法,包括判断AOE网、计算最早发生时间和寻找关键路径的步骤。此外,还给出了C++实现代码来演示这一过程。
摘要由CSDN通过智能技术生成

概念

AOE网,即边表示活动的网,是一个带权的有向无环图,其中顶点表示事件(Event),每个事件表示在它之前的活动已经完成,在它之后的活动可以开始,弧表示活动权表示活动持续的时间

AOE网可用来估算工程的完成时间。由于整个工程只有一个开始点和一个完成点,故在正常的情况(无环)下,网中只有一个入度为零的点(源点)和一个出度为零的点(汇点)。

关键路径: 路径长度最长的路径。

最早发生时间: 假设开始点是v1,从v1到vi的最长路径长度叫做事件vi的最早发生时间。
这个时间决定了所有以vi为尾的弧所表示的活动的最早开始时间。用e(i)表示活动ai最早开始时间,l(i)为一个活动的最迟开始时间,这是在不推迟整个工程完成的前提下,活动ai最迟必须开始进行的时间。两者之差l(i)-e(i)意味着完成活动ai时间余量。l(i)=e(i)的活动叫做关键活动

关键路径上的所有活动都是关键活动,提前完成非关键活动(不在关键路径的活动)并不能加快工程的进度。

求关键路径的算法

  1. 输入e条弧<j, k>,创建有向图的存储结构。
  2. 判断是否为AOE网
    从源点出发,令ve[0]=0,按拓扑顺序求其余各顶点的最早发生时间ve[i]。
    如果得到的拓扑有序序列中顶点个数小于网中顶点数n,则说明网中存在环,不能求关键路径,算法终止,否则转到步骤3。
  3. 从源点出发,循环遍历每一个结点。在循环中同时遍历邻接表中每一个边所存储指向的节点,并且更新其的ve[i].
    :更新时,比较边的权加上更新结点的前一个结点的ve与 该结点本身的ve大小(全部初始化为0),取最大值。

代码

#include<iostream>
#include<cstdlib>
using namespace std;

typedef struct Edge{
    int weight;
    int tailNode;   //边的末顶点
    struct Edge *next;
}Edge;

typedef struct Vertex{
    Edge *nextEdge;
    int InDegree;   //入度
    int OutDegree;  //出度
    int ve;
}Vertex;

typedef struct DirectedGraph{
    Vertex *Vex;
    int VexNum;     //顶点个数
    int EdgeNum;    //边个数
}DirectedGraph;

typedef struct{
    int *Data;
    int Top;
    int MaxSize;
}Stack;

//函数声明
int Max(int a,int b);
DirectedGraph *CreateDirectedGraph(DirectedGraph *g);
int IfAOE(DirectedGraph *g);
void InitStack(Stack *l,int maxsize);
int Pop(Stack *l);
void Push(Stack *l,int e);

DirectedGraph *CreateDirectedGraph(DirectedGraph *g){
    int vexnum,edgenum;
    //cout<<"输入顶点个数与边的个数: ";
    cin>>vexnum;cin>>edgenum;
    g->VexNum=vexnum;   g->EdgeNum=edgenum;
    g->Vex=new Vertex [g->VexNum];
    for(int i=0;i<g->VexNum;i++){
        g->Vex[i].InDegree=0;
        g->Vex[i].OutDegree=0;
        g->Vex[i].ve=0;
        g->Vex[i].nextEdge=NULL;
    }
    for(int k=0;k<g->EdgeNum;k++){
        int i,j,w;
        cin>>i; cin>>j; cin>>w;
        g->Vex[i].OutDegree++;
        g->Vex[j].InDegree++;

        Edge *em=new Edge;   //分配一个结点存储数据
        em->weight=w;
        em->tailNode=j;
        if(g->Vex[i].nextEdge==NULL){
            g->Vex[i].nextEdge=em;
            em->next=NULL;
        }
        else{
            em->next=g->Vex[i].nextEdge;
            g->Vex[i].nextEdge=em;
        }
    }
    return g;
}

int Max(int a,int b){
    return a>b?a:b;
}

void VertexEarliest(DirectedGraph *g){
	int i;
	for(i=0;i<g->VexNum;i++){
		Edge *move=g->Vex[i].nextEdge;
		while(move!=NULL){
			g->Vex[move->tailNode].ve=Max(move->weight+g->Vex[i].ve,g->Vex[move->tailNode].ve);
			move=move->next;
		}	
	}
}

int KeyRoute(DirectedGraph *g){
	for(int i=0;i<g->VexNum;i++){
		if(g->Vex[i].OutDegree==0)
			return g->Vex[i].ve;
	}
	return 0;
}

int IfAOE(DirectedGraph *g){
	//若有多颗树 
   	int OriginalPointNUM=0,MeetingPointNUM=0;
	for(int i=0;i<g->VexNum;i++){
		if(g->Vex[i].InDegree==0)	OriginalPointNUM++;
		if(g->Vex[i].OutDegree==0)	MeetingPointNUM++;	
	}
	if(OriginalPointNUM>1||MeetingPointNUM>1)	return 0;
	
    //若有回路
    int indegree[g->VexNum];    int i;
    for(i=0;i<g->VexNum;i++)
        indegree[i]=g->Vex[i].InDegree;         //给入度数组赋值
    int topo[g->VexNum];    //定义一个拓扑序列数组,存放入度为0的结点
    Stack *S=(Stack*)malloc(sizeof(Stack));
    InitStack(S,g->VexNum);

    for(i=0;i<g->VexNum;i++){
        if(!indegree[i])  Push(S,i);   //入度为0者进栈
    }
    int num=0;      //对输出顶点计数,初始为0

    while(S->Top!=-1){
        topo[num]=Pop(S);
        Edge *p=g->Vex[topo[num]].nextEdge;
        while (p!=NULL){
            indegree[p->tailNode]--;
            if(indegree[p->tailNode]==0) Push(S,p->tailNode);
            p=p->next;
        }
        num++;
    }
    if(num<g->VexNum){
         return 0;
    }
    //若是AOE网,"最早发生时间为:"
    VertexEarliest(g);
    return KeyRoute(g);  
}

void InitStack(Stack *l,int maxsize){
    l->MaxSize=maxsize;
    l->Data=(int *)malloc(l->MaxSize*sizeof(int));
    l->Top=-1;
}

void Push(Stack *l,int e){
    if(l->Top==l->MaxSize) 	return;
    l->Top++;
    *l->Data=e; l->Data++;
}

int Pop(Stack *l){ 
    int a;
    if(l->Top==-1) return 0;
    int temp=*(--l->Data);
    l->Top--;
    return temp;
}


int main(){
    DirectedGraph *g=new DirectedGraph;
    g=CreateDirectedGraph(g);
    int a=IfAOE(g);
    if(a==0)	cout<<"false"<<endl;		//如果不为AOE网,输出false 
	else    cout<<a<<endl;
    return 0;
}

代码的解释后面有时间再细说,如果有疑问我会尽快解答。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西叶胡杨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值