1、AOV和AOE网
AOV是指的用顶点(Vertex)表示活动,用边集表示活动间优先顺序的有向图,图中不会有环。
AOE是指用带权的边集(Edge)表示活动,用顶点表示事件的有向图,边权表示 完成活动所需要的时间。AOE网表示一个工程的进行过程,它也不应该有环,一般来说它只有一个源点(入度为零)和一个汇入点(初度为零),其实AOV网也可以转换为AOE网。
AOE网着重解决的问题有:①工程从开始到结束需要多少时间②工程中哪些分工程是影响全局的。一般来说 第二个问题会转换到最长路径。
2、最长路径
和我们在之前看过的最短路径不同,最长路径,一般代表的是那种不能拖延的工程,如何求最长路径呢?
将所有权值变负,然后用FORD算法算出最小的那个,然后再变正就是了。
3、关键路径
AOE网实际上属于有向无环图,下面给出一个求解有向无环图中最长路径的方法
首先设置两组数组,e和l,第一个表示最早开始的时间,第二个表示最迟开始的时间,如果e==l,则说明这个活动是不能拖延的 ,即为我们所求的关键路径。然后问题来了,怎么求e和l呢?
事件v1在经过活动a之后到达V2,然而是否立即到达顶点V2,也存在拖延的可能性,所以会出现最早发生和 最迟发生两种极端情况,某一个事件最迟发生可以认为下一个事件的最迟开始,设置两个新的数组Ve和Vl,分别表示其最早开始时间和最迟开始时间:
①对于一个活动,在上一个事件最早发生时开始则会得到最早开始时间,e=Ve;
②对于一个事件,他的最迟发生时间就是上个活动最迟开始时间加上路的权值,即 vl=l+w;
然后对于我们的难题就转移到求端点的最早开始和最晚开始时间
假设有k个事件,通过相应的活动到达事件J,假设我们已经得到了每个事件的最早发生时间VE,那么VJ最早发生时间就是各个事件VE+w中的最大值,因为只有所有事件都发生且经过活动到达之后,J才会被激活,所以想要获得VE[J]的正确值,VE[V1]~VE[VK]必须全部都到手 ,通过拓扑排序就可以保证其前驱端点都访问完毕了,但是不可能通过J去拓扑他的前驱端点,因此可以在访问他的前驱端点是,就不断地更新VE[J]。
if(ve[u]+G[u][i].w>ve[j])
{
ve[j]=ve[u]+G[u][i].w;
}
同理,若获得VJ,那么1~K的最晚发生时间也可以确定,这时需要保证他的后继结点都已经被访问完
bool topol()//判断是否非环
{
queue<int >q;
for(int i=0;i<n;i++)
{
if(inDegree[i]==0)//入度为零
{
q.push(i);
}
}
while(!q.empty())
{
int u=q.front();
q.pop;
topOrder.push(u);//加入序列
for(int j=0;j<G[u].size();j++)
{
int v=G[u][j].v;
inDegree[v]--;
if(inDegree[v]==0)//入度为零
{
q.push(v);
}
if(ve[u]+G[u][i].w>ve[j])
{
ve[j]=ve[u]+G[u][i].w;
}
}
}
if(topOrder.size()!=n) return false;
else return true;
}
int CriticalPath()
{
memset(ve,0,sizeof(ve));
if(topol()==false)
{
return -1;
}
fill(vl,vl+n,ve[n-1]);
while(!topOrder.empty())
{
int u = topOrder.top;
topOrder.pop();
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i].v;
if(ve[v]-G[u][i].w<vl[u])//用u的所有后继点来更新vl[u]
{
vl[u]=vl[v]-G[u][i].w;
}
}
}
for(int u=0;u<n;u++)
{
for(int i=0;i<G[u].size();i++)
{
int v =G[u][i].v,w=G[u][i].w;
int e=ve[u],l=vl[v]-w;
if(e==l)
{
printf("%d->%d",u,v);
}
}
}
return ve[n-1];
}