求关键路径:
(1)输入e条弧<j,k>,建立AOE-网的存储结构
(2)从源点v0出发,令ve[0]=0,按拓扑有序求其各顶点的最早发生时间ve[i](1<=i<=n-1).如果得到的拓扑有序序列中顶点个数小于顶点数n,则说明网中存在环,不能求关键路径,算法终止;否则执行步骤(3);
(3)从汇点vn出发,令vl[n-1]=ve[n-1],按逆拓扑有序求其各顶点的最迟发生时间vl[i](n-2>=i>=2);
(4)根据各顶点的ve和vl值,求每条弧的最早开始时间ee和最迟开始时间el,若某条弧满足条件ee=el,则为关键活动。
如上所述,计算各顶点的ve和vl值是在拓扑排序的过程中进行的,需对拓扑排序的算法作如下修改:(a)在拓扑排序之前设初值,令ve[i]=0(0<=i<=n-1);(b)在算法中增加一个计算vj的直接后继vk的最早发生时间的操作:若ve[j]+dut(<j,k>)>ve[k],则ve[k]=ve[j]+dut(<j,k>); (c) 为了能按逆拓扑有序序列的顺序计算各顶点的vl值,需记下在拓扑排序的过程中求得的拓扑有序序列,这需要在拓扑排序算法中,增设一个栈以记录拓扑排序序列,则在计算求得各顶点的ve值之后,从栈顶至栈底便为逆拓扑有序序列。
题目描述
一个无环的有向图称为无环图(Directed Acyclic Graph),简称DAG图。
AOE(Activity On Edge)网:顾名思义,用边表示活动的网,当然它也是DAG。与AOV不同,活动都表示在了边上,如下图所示:
如上所示,共有11项活动(11条边),9个事件(9个顶点)。整个工程只有一个开始点和一个完成点。即只有一个入度为零的点(源点)和只有一个出度为零的点(汇点)。
关键路径:是从开始点到完成点的最长路径的长度。路径的长度是边上活动耗费的时间。如上图所示,1 到2 到 5到7到9是关键路径(关键路径不止一条,请输出字典序最小的),权值的和为18。
输入
输出
示例输入
9 11 1 2 6 1 3 4 1 4 5 2 5 1 3 5 1 4 6 2 5 7 9 5 8 7 6 8 4 8 9 4 7 9 2
示例输出
18 1 2 2 5 5 7 7 9
提示
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
struct Arcnode
{
int v;
int w;
Arcnode *next;
};
struct Vnode
{
int u;
int Ind;
Arcnode *first;
}head[20000];
struct node
{
int l,r;
};
int ve[20000],vl[20000];
int sta[20000],top;
int topo(int n)
{
int i,j;
int sta1[12000],top1=0;
memset(ve,0,sizeof(ve));
for(i=1;i<=n;i++)
if(head[i].Ind==0)
sta1[++top1]=head[i].u;
int cont=0;
while(top1>0)
{
j=sta1[top1--];
sta[++top]=j;
cont++;
Arcnode *p=head[j].first;
for(;p;p=p->next)
{
int k=p->v;
int dut=p->w;
head[k].Ind--;
if(head[k].Ind==0)
sta1[++top1]=k;
if(ve[k]<ve[j]+dut)
ve[k]=ve[j]+dut;
}
}
if(cont<n)
return false;
else
return true;
}
int CriticalPath(int n)
{
if(!topo)
return false;
int i,j,k;
node out[60000];
int len=-1,ee,el;
for(i=1;i<=n;i++)
vl[i]=ve[n];
Arcnode *p;
while(top>0)
{
for(j=sta[top--],p=head[j].first;p;p=p->next)
{
k=p->v;
int dut=p->w;
if(vl[j]>vl[k]-dut)
vl[j]=vl[k]-dut;
}
}
for(j=1;j<=n;j++)
for(p=head[j].first;p;p=p->next)
{
k=p->v;
int dut=p->w;
ee=ve[j];
el=vl[k]-dut;
if(ee==el)
{
out[++len].l=j;
out[len].r=k;
//弧头和弧尾相等的弧可能有多条,需要在循环内判断
if(out[len].l==out[len-1].l)
{
if(out[len].r<out[len-1].r)
out[len-1].r=out[len].r;
len--;
}
if(out[len].r==out[len-1].r)
{
if(out[len].l<out[len-1].l)
out[len-1].l=out[len].l;
len--;
}
}
}
printf("%d\n",vl[n]);
for(i=0;i<=len;i++)
printf("%d %d\n",out[i].l,out[i].r);
}
int main()
{
int n,m,i,j;
int u,v,w;
while(~scanf("%d%d",&n,&m))
{
top=0;
for(i=1;i<=n;i++)
{
head[i].u=i;
head[i].Ind=0;
head[i].first=NULL;
}
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
Arcnode *p=new Arcnode;
p->v=v;
p->w=w;
p->next=head[u].first;
head[u].first=p;
head[v].Ind++;
}
topo(n);
CriticalPath(n);
}
return 0;
}