AOE-网
(Activity on Edge),即边表示活动的网。若在带权的有向无环图G中,顶点表示事件(Event),弧表示活动(Activity),权(Weight)表示持续的时间,则此有向图称为边表示活动的网,即AOE-网。
AOE-
网的用途:
用来估算工程的完成时间
分析关键路径的目的:辨别哪些是关键活动,以便争取提高关键活动的工效,
缩短整个工期。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <stack>
using namespace std;
#define MAXNODE 1000// 图中顶点的最大个数
typedef int infotype;
typedef int vertype;
struct ArcNode//边节点类型
{
int adjvex;//该边的终点编号
ArcNode *next;//指向下一条边的指针
infotype info;//该边的相关信息
};
struct VerNode//表头结点
{
vertype vertex;// 顶点信息
ArcNode *firstarc;// 指向第一个邻接点的指针
};
struct AlGraph//邻接表
{
VerNode vertices[MAXNODE];//邻接表
int vexnum,arcnum;// 顶点和边的数目
};
//事件的:ve最早发生时间,vl最迟发生时间;活动的:e最早加工时间,l最迟加工时间
int ve[MAXNODE],vl[MAXNODE],e,l;
AlGraph CreatAdjList(AlGraph g)//建立有向图的邻接表存储结构
{
int n;
cout<<"输入顶点个数:"<<endl;
cin>>n;
cout<<"输入顶点的名称:"<<endl;
for(int i=1;i<=n;i++)
{
cin>>g.vertices[i].vertex;//输入顶点信息
g.vertices[i].firstarc=NULL;//初始化每个链表为空
}
int v1,v2,info;
cout<<"输入图的边以及权值,两个顶点之一为0,表示输入结束。"<<endl;
cin>>v1>>v2>>info;//输入一条边依附的两个顶点序号,以及权值
int e=0;//图的边数
while(v1!=0&&v2!=0)//题目要求两顶点之一为0表示结束
{
//i=GraphLocateVertex(g,v1);
//j=GraphLocateVertex(g,v2);
ArcNode *p= (ArcNode*)malloc(sizeof(ArcNode));
//用头插法插入结点以建立链表
p->adjvex=v2;
p->next=g.vertices[v1].firstarc;
p->info=info;
g.vertices[v1].firstarc=p;
e++;
cin>>v1>>v2>>info;
}
g.vexnum=n;
g.arcnum=e;
return g;
}
void CountInDegree(AlGraph g,int *indegree)//取得图中各个顶点的入度
{
for(int i=1;i<=g.vexnum;i++)
{
indegree[i]=0;
for(int j=1;j<=g.vexnum;j++)//遍历图
{
ArcNode * p = g.vertices[j].firstarc;
for(;p!=NULL;p=p->next)
{
int k = p->adjvex;
if(g.vertices[k].vertex==g.vertices[i].vertex)indegree[i]++;
}
}
//cout<<indegree[i]<<endl;
}
}
//假设第 i 条弧为:< j, k >
//则第 i 项活动:
//“活动(弧)”的最早开始时间为:e(i)
//e(i)=ve(j)
//“活动(弧)”的最迟开始时间为:l(i)
//l(i)=vl(k)-dut(< j, k >)
//事件发生时间的计算公式:
//ve(源点)=0
//ve(k)=Max{ve(j)+dut(< j,k >) }
//vl(汇点)=ve(汇点)
//vl(j)=Min{ vl(k)-dut( <j,k >)}
void TopologicalSort(AlGraph g,stack<vertype> &t)//拓扑排序算法
{
int indegree[MAXNODE];//保存各个顶点的入度信息
CountInDegree(g,indegree);//对各顶点求入度
stack<vertype> s;
for(int i=1;i<=g.vexnum;i++)
if(!indegree[i])s.push(g.vertices[i].vertex);//入度为0者进栈
int count=0;
for(int j=1;j<=g.vexnum;j++)
{
ve[j]=0;
}
while(!s.empty())
{
vertype v = s.top();
s.pop();
t.push(v);//将拓扑排序逆序保存到t中
//cout<<v<<" ";//输出顶点
count++;
for(ArcNode *p = g.vertices[v].firstarc;p!=NULL;p=p->next)
{
//对i号顶点的每个邻接点的入度减1,新产生的入度为0的顶点进栈
int k = p->adjvex;
if(!(--indegree[g.vertices[k].vertex]))s.push(g.vertices[k].vertex);
if(ve[v]+p->info>ve[k])ve[k]=ve[v]+p->info;//求事件的最早发生时间
}
}
if(count<g.vexnum)cout<<"图中存在回路"<<endl;
else cout<<"存在拓扑序列"<<endl;
}
void CriticalPath(AlGraph g)//输出g的各项关键活动
{
stack<vertype> t;
TopologicalSort(g,t);
for(int i=1;i<=g.vexnum;i++)
{
if(i==t.top())
vl[i]=ve[i];//初始化顶点事件的最迟发生事件
else vl[i]=1000000;//无穷大
}
while(!t.empty())//求事件的最晚发生时间
{
vertype v = t.top();
t.pop();
//cout<<v<<" ";
for(ArcNode *p = g.vertices[v].firstarc;p!=NULL;p=p->next)
{
int k=p->adjvex;
int dut=p->info;
if(vl[k]-dut<vl[v])vl[v]=vl[k]-dut;//取vl的最小值
}
}
for(int p=1;p<=g.vexnum;p++)//输出事件最早最晚发生时间
{
cout<<p<<" "<<"最早 "<<ve[p]<<" 最晚 "<<vl[p]<<endl;
}
for(int j=1;j<=g.vexnum;j++)//求e,l和关键活动
{
for(ArcNode *p = g.vertices[j].firstarc;p!=NULL;p=p->next)
{
int k=p->adjvex;
int dut=p->info;
e=ve[j];l=vl[k]-dut;
int tag=(e==l)?1:0;
cout<<j<<"->"<<k<<" ";
cout<<"活动最早开始时间: "<<e<<" ";
cout<<"活动最晚开始时间: "<<l<<" ";
if(tag)cout<<"关键路径"<<endl;
else cout<<"不是关键路径"<<endl;
}
}
}
int main()
{
AlGraph g;
g=CreatAdjList(g);
cout<<"图建立成功."<<endl;
CriticalPath(g);
return 0;
}