关键路径在算法题中的应用

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];
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值