题目描述
下图是一个有向无环图,节点内的数字表示该节点的序号,节点之间的连接线表示节点之间的连接方式,连接线上方的黑色数字表示该连接线的权重。
最早发生时间:从前往后,前驱节点到当前节点所需时间,取最大值
本题要求:求出有向无环图中每一个节点的最早发生时间(示例图中每一个节点的最早发生时间以节点上方的黄色数字标出)
输入格式
第一行为2个正整数m和n,分别表示有向无环图的节点个数和边的数量。
接下来n行,代表n条边。分别是起点、终点、权重,以空格分隔。
(m<50,n<100)
输出格式
按行输出有向无环图中每一个节点最早发生时间,按照节点的序号从小到大输出。
如样例中,0、1、2、3、4号节点的最早发生时间分别是0、3、3、7、11。
则按行输出0、3、3、7、11。
输入样例
5 6
0 1 3
0 2 3
1 3 2
2 3 4
2 4 4
3 4 4
输出样例
0
3
3
7
11
数据范围与提示
代码展示
#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;
string vexInfo[INFO_MAX_SIZE];
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,const Graph &g,temp &t){
preInitGraph(G,g);
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;
ArcNode *p=new ArcNode();
p->nextarc=NULL;
p->weight=c;
p->adj=b;
ArcNode *q=G.vexes[a].firstarc;
if(G.vexes[a].firstarc==NULL)
G.vexes[a].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>> CriticalPath(linkGraph G){
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;
}
}
//按逆拓扑序计算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;
}
}
//遍历所有弧,计算弧的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));
}
}
}
//本题输出在这里呀
for(int i=0;i<G.vexnumber;i++){
cout<<ve[i]<<endl;
}
return aArcs;
}
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);
CriticalPath(LG);
return 0;
}