AOE/AOV网下的关键路径

AOE/AOV网下的关键路径

在做那本王道考研数据结构书的时候发现这个东西,以前没听说过(太菜了

1.定义

一般而言这个模型可以用来表示一个项目的子项之间的依赖关系,用来管理项目进度。

1.1 AOV网

AOV网指的是Activity-On-Vertex,用边表示事件,用点表示事件之间的关系(活动),边权是活动时间。这是一个DAG(有向无环图)

1.2 AOE网

AOE网指的是Activity-On-Edge,用点表示事件,用边表示事件之间的关系(活动),边权是活动时间。这也是一个DAG(有向无环图)

1.3 关键路径

如果改变一条路径上的任意一条边的边权,都可以加速项目的最终进度,那么这条路径被称为关键路径。

2.计算方法

计算关键路径事实上只是在DAG上的简单dp,首先计算一个事件的最早开始时间,然后计算一个事件的不会影响到最终项目进度的最晚开始时间,当最早开始时间等于最晚开始时间,那么这个点是一个关键的点。所有的关键点一定会组成一颗树。树上的所有路径都是关键路径。

首先计算拓扑序,然后在拓扑序上正向递推一个事件的最早开始时间
f o r   e a c h   e d g e   < u → v >   : m i n S t a r t T i m e [ v ] = M a x ( m i n S t a r t T i m e [ v ] , m i n S t a r t T i m e [ u ] + w [ u ] [ v ] ) for\ each\ edge\ <u\rarr v>\ : \\ minStartTime[v] = Max(minStartTime[v],minStartTime[u]+w[u][v])\\ for each edge <uv> :minStartTime[v]=Max(minStartTime[v],minStartTime[u]+w[u][v])
第一个点的 minStartTime = 0

然后在逆拓扑序上递推最迟开始时间
f o r   e a c h   e d g e   < u → v >   : m a x S t a r t T i m e [ u ] = M i n ( m a x S t a r t T i m e [ u ] , m a x S t a r t T i m e [ v ] − w [ u ] [ v ] ) for\ each\ edge\ <u\rarr v>\ : \\ maxStartTime[u] = Min(maxStartTime[u],maxStartTime[v]-w[u][v])\\ for each edge <uv> :maxStartTime[u]=Min(maxStartTime[u],maxStartTime[v]w[u][v])
最后一个点的 maxStartTime = minStartTime

3.代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
const int MAXN = 1e6+7, INF = 0x3f3f3f3f;
template <typename _TP>
inline _TP qread(_TP &X){
	char ch=0;int w;X=0;
	while(!isdigit(ch)){w=ch=='-';ch=getchar();}
	while(isdigit(ch)){X=(X<<1)+(X<<3)+(ch^'0');ch=getchar();}
	X=w?-X:X;
	return X;
}
queue <int> q;
vector <int> v[MAXN],d[MAXN],pre[MAXN],predis[MAXN];
int ind[MAXN];
inline void adde(const int x,const int y,const int z){ 
	v[x].push_back(y);
	d[x].push_back(z);
	pre[y].push_back(x);
	predis[y].push_back(z);
	ind[y]++;
}
int topoOrder[MAXN],vis[MAXN],cntTopo=0;
void topoSort(int s){
	vis[s]=1;
	q.push(s);
	int nxt;
	while(!q.empty()){
		s = q.front();
		vis[s]=1; 
		q.pop();
		topoOrder[++cntTopo]=s;
		for(int i=0;i<v[s].size();i++){
			nxt = v[s][i];
			if(!vis[nxt]){ 
				if(!(--ind[nxt])){
					q.push(nxt);
				}
			}
		}
	}
}
int minStart[MAXN],maxStart[MAXN],n,m;
bool iscritical [MAXN];
inline int Max(const int a,const int b){
	return a>b?a:b;
}
inline int Min(const int a,const int b){
	return a<b?a:b;
}
inline void PRINT(const int *tmp){
	for(int i=1;i<=n;i++){
		cout<<tmp[i]<<' ';
	}
	cout<<'\n';
}
int main(){
	int x,y,z;
	qread(n);qread(m);
	for(int i=1;i<=m;i++){
		qread(x);qread(y);qread(z);
		adde(x,y,z);
	}
	int s=1;		//start node
	topoSort(s);
	cout<<"topoOrder: ";
	PRINT(topoOrder); 
	int now,nxt;
	for(int i=1;i<=n;i++){
		now = topoOrder[i];
		for(int j=0;j<v[now].size();j++){
			nxt = v[now][j];
			minStart[nxt] = Max(minStart[nxt],minStart[now]+d[now][j]);
		}
	}
	cout<<"minStart: ";
	PRINT(minStart); 
	memset(maxStart,0x3f,sizeof(maxStart));
	maxStart[topoOrder[n]] = minStart[topoOrder[n]];
	for(int i=n;i>=1;i--){
		now = topoOrder[i];
		for(int j=0;j<pre[now].size();j++){
			nxt = pre[now][j];
			maxStart[nxt] = Min(maxStart[nxt],maxStart[now]-predis[now][j]);
		}
	}
	cout<<"maxStart: ";
	PRINT(maxStart); 
	for(int i=1;i<=n;i++){		//go through all edges
		for(int j=0;j<v[i].size();j++){
			nxt = v[i][j];
			int minHappen = minStart[i];
			int maxHappen = maxStart[nxt]-d[i][j];
			if(maxHappen - minHappen == 0){
				iscritical[i] = iscritical [j] = true;
			}
		}
	}
	cout<<"critical point: ";
	for(int i=1;i<=n;i++){
		if(iscritical[i])cout<<i<<' ';
	}
	return 0;
}

4.样例

10 14
1 2 5
1 3 6
2 5 3
3 5 6
3 4 3
4 5 3
4 7 1
4 8 4
5 6 4
5 7 2
6 10 4
7 9 5
8 9 2
9 10 2

第一行n,m是点的数量和边的数量

样例来自王道数据结构考研复习指导的习题13

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值