用Topo序列求关键路径

//时间复杂度(n+e)  n:顶点数	e:边数
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>

using namespace std;

const int MAXN=10000;

struct Node{
	int x;
	int v;
};

vector<Node> Map[MAXN];
stack<int> num,T;						//T为拓扑序列顶点栈,num为零入度顶点栈
int cnt[MAXN],ve[MAXN],vm[MAXN];		//cnt表示各个顶点当前的入度,ve表示各个顶点事件的最早发生时间
										//vm表示各个顶点事件的最迟发生时间
int n,m;

bool Topo()
{
	int i,j,count=0;
	Node tmp;
	while(!T.empty())
		T.pop();
	while(!num.empty())
		num.pop();

	for(i=1;i<=n;i++)
	{
		if(cnt[i]==0)
			num.push(i);
	}

	while(!num.empty())
	{
		T.push(num.top());
		num.pop();
		++count;
		for(i=0;i<Map[T.top()].size();i++)
		{
			tmp=Map[T.top()][i];
			cnt[tmp.x]--;
			if(cnt[tmp.x]==0)
				num.push(tmp.x);
			if(ve[tmp.x]<tmp.v+ve[T.top()])
				ve[tmp.x]=tmp.v+ve[T.top()];
		}
	}
	if(count<n)
		return false;
	return true;
}

bool CriticalPath()
{
	int i,j;
	Node tmp;
	if(Topo()==false)
		return false;
	for(i=1;i<=n;i++)					//初始化顶点事件的最迟发生时间
		vm[i]=ve[n];
	while(!T.empty())					//按拓扑逆序求各顶点的vm值
	{
		j=T.top();
		T.pop();
		for(i=0;i<Map[j].size();i++)
		{
			tmp=Map[j][i];
			if(vm[j]>vm[tmp.x]-tmp.v)
				vm[j]=vm[tmp.x]-tmp.v;
		}
	}

	printf("\n");
	for(i=1;i<=n;i++)									//求关键活动
	{
		for(j=0;j<Map[i].size();j++)
		{
			tmp=Map[i][j];
			if(ve[i]==vm[tmp.x]-tmp.v)
				printf("%d %d %d\n",i,tmp.x,tmp.v);		//输出关键路径
		}
	}

}

int main()
{
	int i,j,a;
	Node tmp;
	while(scanf("%d%d",&n,&m)==2)
	{
		for(i=1;i<=n;i++)
		{
			Map[i].clear();
			cnt[i]=0;
			ve[i]=0;
		}

		for(i=1;i<=m;i++)
		{
			scanf("%d%d%d",&a,&tmp.x,&tmp.v);
			Map[a].push_back(tmp);
			cnt[tmp.x]++;				//求各定点的入度
		}

		if(CriticalPath()==false)
			printf("ERROR\n");
		else
		{
			printf("\n");
			for(i=1;i<=n;i++)
			{
				printf("%d %d %d\n",i,ve[i],vm[i]);
			}
		}
	}

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值