关键路径、最长路径

测试用例:顶点数量n,路径数量m

接下来m行:format:顶点a->顶点b 路径长度

6 8
0 1 3
0 2 2
0 3 2
2 3 5
1 4 3
3 5 2
2 5 3
4 5 1

关键路径一定是有向无环图

代码段

#include <cstdio>
#include <cstring>
#include <iostream>
#include <math.h>
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <map>
#include <vector>
#include <set>
#include <stack>
#include <queue>
using namespace std;
const int maxn = 10010;
struct node{
	int v,w;//编号 
};
int indegree[maxn]={0};
//事件最早发生时间,事件最晚发生时间 
int ve[maxn],vl[maxn];
//g[i]中保存了i指向的顶点node,其中有指向的顶点编号以及该边权重 
vector<node> g[maxn];
stack<int> topOrder; 
int n,m;
bool tologicalSort(){
	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();
		for(int i=0;i<g[u].size();i++){
			int v=g[u][i].v;
			indegree[v]--;
			if(indegree[v]==0){
				q.push(v);
			}
			//ve[v] = max(ve[v的前驱u]+length(u,v));
			//根据拓扑顺序,求最早事件发生的最早时间 
			if(ve[u]+g[u][i].w>ve[v]){
				ve[v] = ve[u]+g[u][i].w;
			}
		}
		topOrder.push(u);
	}
	if(topOrder.size()==n) return true;
	else return false;
}
int CriticalPath(){
	memset(ve,0,sizeof(ve));
	if(!tologicalSort()) return -1;
	fill(vl,vl+n,ve[n-1]);//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;
			//逆拓扑排序,从后往前计算事件最晚开始时间
			//vl[u] = min(vl[后继v]-length[u,v]) 
			if(vl[u]>vl[v]-g[u][i].w){
				vl[u] = vl[v]-g[u][i].w;
			}
		}
	}
	//遍历邻接表所有边,计算所有活动的最早开始时间最晚开始时间
	//e==l时,是关键活动 (路径) 
	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\n",u,v);
		}
	} 
	return ve[n-1];
} 
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<m;i++){
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		node Node;
		Node.v = b;
		Node.w = c;
		g[a].push_back(Node);
		indegree[b]++;
	}
	int a =CriticalPath();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值