问题 H: 图-边的最早发生时间

题目描述

下图是一个有向无环图,节点内的数字表示该节点的序号,节点之间的连接线表示节点之间的连接方式,连接线上方的黑色数字表示该连接线的权重。
本题要求:求出有向无环图中每一个边的最早发生时间(示例图中每一个边的最早发生时间以边旁边的黄色数字标出)

 

输入格式

第一行为2个正整数m和n,分别表示有向无环图的节点个数和边的数量。
接下来n行,代表n条边。分别是起点、终点、权重,以空格分隔。
(m<50,n<100)
 

输出格式

按行输出有向无环图中每一个边的最早发生时间,按照输入样例中边的输入次序输出。
如输入样例中,边的输入次序为:
0-->1
0-->2
1-->3
2-->3
2-->4
3-->4
则输出样例中,按行分别输出上述边的最早发生时间:0、0、3、3、3、7

输入样例

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

输出样例  

0
0
3
3
3
7

数据范围与提示

 

代码展示 

注意:本题要求输出顺序与输入边顺序一致,不是结点从小到大顺序。

#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

#define INFO_MAX_SIZE 20
#define MAX_SIZE 200
 //领接矩阵存储的图
struct Graph{
	int vexNumber;
	int weight;
	int adjMatrix[MAX_SIZE][MAX_SIZE];
};
 //弧结点定义
struct ArcNode{
	int weight;//弧上的信息部分
	int adj;//邻接点的序号
	ArcNode *nextarc;
};
 //顶点结点定义
struct VexNode{
	string Info;
	ArcNode *firstarc;
};
 //领接表结构的图的定义
struct linkGraph{
	VexNode *vexes;
	int vexnumber;
};

struct tempNode{
	int col;
	int row;
	int weight;
	//tempNode *next;
};

struct temp{
	int num;
	tempNode *docu;
};


int preInitGraph(linkGraph &G,const Graph &g){
	G.vexes=new VexNode[g.vexNumber];
	G.vexnumber=g.vexNumber;
	for(int i=0;i<g.vexNumber;i++){
		G.vexes[i].firstarc=NULL;
	}
	return 0;
}
//将邻接矩阵存储的图转换为领接表存储的图
void InitGraph(linkGraph &G,Graph &g,temp &t){
	preInitGraph(G,g);
	g.adjMatrix[G.vexnumber][G.vexnumber]={0};
	for(int i=0;i<t.num;i++){
		int a,b,c;
		a=t.docu[i].row;b=t.docu[i].col;c=t.docu[i].weight;
		g.adjMatrix[a][b]=c;
	}
	for(int i=0;i<G.vexnumber;i++){
		for(int j=0;j<G.vexnumber;j++){
			if(g.adjMatrix[i][j]!=0){
				ArcNode *p=new ArcNode();
				p->nextarc=NULL;
				p->weight=g.adjMatrix[i][j];
				p->adj=j;
				ArcNode *q=G.vexes[i].firstarc;
				if(G.vexes[i].firstarc==NULL)
					G.vexes[i].firstarc=p;
				else{
					while(q->nextarc!=NULL){
						q=q->nextarc;
					}
					q->nextarc=p;
				}
			}
		}
	}
	
}

int TopologicalSort(linkGraph LG,int Topo[]){
	vector<int>indegree(LG.vexnumber);
	for(int i=0;i<LG.vexnumber;i++) indegree[i]=0;
	for(int i=0;i<LG.vexnumber;i++){
		for(ArcNode *p=LG.vexes[i].firstarc;p!=nullptr;p=p->nextarc)
			indegree[p->adj]++;
	}
	//入度为零的点入栈
	stack<int>s;
	for(int i=0;i<LG.vexnumber;i++){
		if(indegree[i]==0)  s.push(i);
	}

	int i=0;
	while(!s.empty()){
		int j=s.top();s.pop();
		Topo[i++]=j;
		//将Vj邻接点入度减一,减为0的入栈
		for(ArcNode *p=LG.vexes[j].firstarc;p!=nullptr;p=p->nextarc){
			indegree[p->adj]--;
			if(indegree[p->adj]==0)  s.push(p->adj);
		}
	}
	if(i==LG.vexnumber)  return 0;
	else  return 1;
}

//输出领接表存储的图
void PrintGraph(const linkGraph &G){
	for(int i=0;i<G.vexnumber;i++){
		cout<<G.vexes[i].Info;
		ArcNode *p=G.vexes[i].firstarc;
		cout<<i;
		while(p!=NULL){
			cout<<" --> "<<p->adj;
			p=p->nextarc;
		}
		cout<<endl;
	}
}


//vector<pair<int,int>>
void CriticalPath(linkGraph G,temp t){
	int Topo[G.vexnumber];
	if(TopologicalSort(G,Topo)){
		cout<<"Impossible"<<endl;
		return ;
	}
	vector<pair<int,int>>aArcs;
	//统计入度
	vector<int>indegree(G.vexnumber);
	for(int i=0;i<G.vexnumber;i++)  indegree[i]=0;
	for(int i=0;i<G.vexnumber;i++){
		for(ArcNode *p=G.vexes[i].firstarc;p!=nullptr;p=p->nextarc)
			indegree[p->adj]++;
	}
	//入度为0进栈
	stack<int>s;
	for(int i=0;i<G.vexnumber;i++){
		if(indegree[i]==0)  s.push(i);
	}
	//拓扑排序,计算ve
	vector<int>ve(G.vexnumber);
	for(int i=0;i<G.vexnumber;i++) ve[i]=0;
	stack<int>s2;//记录拓扑序
	while(!s.empty()){
		int i=s.top();s.pop();
		s2.push(i);

		//遍历Vi邻接点
		for(ArcNode *p=G.vexes[i].firstarc;p!=nullptr;p=p->nextarc){
			//邻接点入度减一,为0入栈
			int j=p->adj;
			indegree[j]--;
			if(indegree[j]==0)  s.push(j);
			//修正Vj的Ve值
			if(ve[i]+p->weight>ve[j]){
				ve[j]=ve[i]+p->weight;
			}
		}
	}

	//test
	// for(int i=0;i<G.vexnumber;i++){
	// 	cout<<"ve["<<i<<"]="<<ve[i]<<endl;
	// }

	int path[G.vexnumber][G.vexnumber]={0};
	for(int i=0;i<G.vexnumber;i++){
		for(ArcNode *p=G.vexes[i].firstarc;p!=nullptr;p=p->nextarc){
			path[i][p->adj]=ve[i];
		}
	}
	//可以按照题目要求顺序输出的办法
	for(int i=0;i<t.num;i++){
		int a=t.docu[i].row;
		int b=t.docu[i].col;
		//int target=path[a][b];
		cout<<path[a][b]<<endl;
	}

	
	//按逆拓扑序计算vl,终点的ve值作为vl的初值
	vector<int>vl(G.vexnumber);
	int maxve=ve[s2.top()];
	for(int i=0;i<G.vexnumber;i++) vl[i]=maxve;
	while(!s2.empty()){
		int i=s2.top();s2.pop();
		//用Vi的邻接点来修正Vi的Vl值
		for(ArcNode *p=G.vexes[i].firstarc;p!=nullptr;p=p->nextarc){
			int j=p->adj;
			if(vl[j]-p->weight<vl[i])
				vl[i]=vl[j]-p->weight;
		}
	}
    // test
	// for(int i=0;i<G.vexnumber;i++){
	// 	cout<<vl[i]<<endl;
	// }
	
	int sum=0;
	//遍历所有弧,计算弧的e和l值,挑选关键弧(e和l相等的弧)
	for(int i=0;i<G.vexnumber;i++){
		for(ArcNode *p=G.vexes[i].firstarc;p!=nullptr;p=p->nextarc){
			int e=ve[i];
			int l=vl[p->adj]-p->weight;
			if(e==l){
				//记录一条关键弧
				aArcs.push_back(make_pair(i,p->adj));
				sum+=p->weight;
			}
		}
	}
	// pair<int,int>pr=aArcs.back();
	
}


int main(){
	//freopen("/config/workspace/test/test","r",stdin);
	int n,m;
	cin>>n>>m;

	Graph G;
	G.vexNumber=n;
	
	temp t;
	t.num=m;
	t.docu=new tempNode[m];
	for(int i=0;i<m;i++){
		int a,b,c;
		cin>>a>>b>>c;
		t.docu[i].row=a;
		t.docu[i].col=b;
		t.docu[i].weight=c;
	}
	linkGraph LG;
	InitGraph(LG,G,t);
	//test
	//PrintGraph(LG);
	CriticalPath(LG,t);
	
	
	return 0;
}

//闲叙题外话:没有唇膏不行啊,真的太干啦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值