浅看拓扑序列
AOE:
有向无环图中的顶点表示活动或事件,有向边(弧)表示了事件发生的先后关系
注:(A---->B 这个为弧,A为弧尾,B为弧头)
拓扑序列:
给定一个包含一个有向图所有顶点的序列,如果图中任意两个顶点Vi到Vj有一条路径,且在该序列中vi排在vj的前面
注:该序列不唯一
应用:
判断图是否存在环(用一个计数器记录每次出栈或出队次数,小于顶点数则存在环)
求关键路径
算法步骤
1、对于每一个点用一个数组d[i]记录i号顶点的入度
2、一遍循环找到入度为0 的顶点入栈(队列)
3、循环:如果栈(队列)非空
{
取出栈顶(队首)t,输出(记录)
将领接表中以t为起点的边的终点的入度-1(相当于删除该顶点即它的所有出边)
如果该终点的入度为0 则入栈(入队)
}
注:手写数组队列时,整个过程结束后,队列从0到队尾所保存的就是拓扑序列
模板:
关键路径:
AOE:
有向图中顶点表示事件,边表示活动,边权表示活动持续时间
源点:
入度为0的事件
汇点:
出度为0的事件
关键路径:
测试数据:
6 8
0 1 2
0 2 15
1 3 10
1 4 19
2 1 4
2 4 11
3 5 6
4 5 5
bool creaticalpath()
{
if(topsort()){
cout<<"拓扑序列为:"<<endl;
for(int i=0;i<n;i++)
cout<<topo[i]<<"\t";
cout<<endl;
}
else {
cout<<"该图有环,无拓扑序列"<<endl;
return 0;
}
for(int i=0;i<n;i++)//初始化最早发生时间
ve[i]=0;
for(int j=0;j<n;j++){//求每个事件最早发生时间
int u=topo[j];
for(int i=h[u];i;i=ne[i])
{
int v=e[i],t=w[i];
ve[v]=max(ve[u]+w,ve[v]);
}
}
for(int i=0;i<n;i++)//初始化每个事件最迟发生时间
vl[i]=ve[n-1];
for(int j=n-1;j>=0;j--)
{
int u=topo[j];
for(int i=h[u];i;i=ne[i])
{
int v=e[i],t=w[i];
vl[u]=min(vl[u],vl[v]+t);
}
}
cout<<"事件的最早发生时间和最迟发生时间:"<<endl;
for(int i=0;i<n;i++)
cout<<ve[i]<<"\t"<<vl[i]<<endl;
for(int u=0;u<n;u++){//对u的弧尾所有活动求最早开始时间和最迟开始时间
for(int i=h[u];i;i=ne[i]){
int v=e[i],t=w[i];
int estart=ve[u];
int end=vl[v]-t;
if(estart==end)
cout<<"<"<<u<<","<<v<<">"<<endl;
}
}
return 1;
}