题目描述
下图是一个有向无环图,节点内的数字表示该节点的序号,节点之间的连接线表示节点之间的连接方式,连接线上方的黑色数字表示该连接线的权重。
本题要求:求出有向无环图中每一个边的最早发生时间(示例图中每一个边的最早发生时间以边旁边的黄色数字标出)
输入格式
第一行为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;
}
//闲叙题外话:没有唇膏不行啊,真的太干啦。