关键路径
Problem Description
给定一个有N个顶点、M条边的有向图,顶点下标为从1到N,每条边都有边权。判断这个有向图是否是有向无环图,如果是的话,请处理K个查询,每个查询为图中的一条边,求这条边的最早发生时间和最晚发生时间。最后再输出图中的所有关键路径。
Input
每个输入文件中一组数据。
第一行为两个整数N、M,表示有向无环图的顶点数和边数(1<=N<=1000, 0<=M<=N*(N-1)),顶点编号为从1到N。
接下来M行,每行为三个正整数u、v、w(1<=u,v<=N,0<w<=20,u!=v),分别表示有向边的起点、终点、边权。数据保证不会有两条起点和终点都相同的边。
然后是一个正整数K(1<=K<=1000),表示查询个数。
接着是K行,每行为两个正整数u、v,分别表示查询边的起点和终点。数据保证查询边一定是图上存在的边。
Output
如果给出的图不是有向无环图,那么在一行里输出NO,后面的查询结果和关键路径均不需要输出;
如果给出的图是有向无环图,那么在一行里输出YES,接着输出下面的内容:
每个查询一行,输出查询边的最早发生时间和最晚发生时间;
之后一行输出一个整数:关键路径上的边权之和;
最后若干行输出所有关键路径,每行表示其中一条,格式为用->连接的顶点编号。注意,如果有两条关键路径a[1]->a[2]->...->a[k]->a[k+1]->...与b[1]->b[2]->...->b[k]->[k+1]->...,满足a[1]==b[1]、a[2]==b[2]、...、a[k]==b[k]、a[k+1]<b[k+1],那么把关键路径a优先输出。数据保证关键路径条数不超过10000条。
Sample Input 1
4 5 1 2 3 1 3 2 1 4 5 2 4 1 3 4 3 2 1 3 2 4
Sample Output 1
YES 0 0 3 4 5 1->3->4 1->4
Sample Input 2
3 3 1 2 3 2 3 1 3 2 2 2 1 2 2 3
Sample Output 2

1 #include <cstdio> 2 #include <iostream> 3 #include <vector> 4 #include <algorithm> 5 #include <queue> 6 #include <stack> 7 using namespace std; 8 typedef struct NODE{ 9 int w, v; 10 NODE(){} 11 NODE(int tmpEnd, int tmpW):v(tmpEnd),w(tmpW){} 12 }node; 13 typedef struct EDGE{ 14 int start, end; 15 }edge; 16 vector<node> vexEdgeVec[1010]; 17 vector<int> inDegreeVec(1010, 0), inDegOriginVec(1010, 0); 18 stack<int> topologicalStack; 19 vector<int> minStartTimeVec(1010), maxEndTimeVec(1010); 20 vector<edge> edgeQueryVec; 21 vector<int> tmpPathVec; 22 vector<int> criticalPathPreVec[1010]; 23 int e[1010][1010], l[1010][1010]; 24 int N, M, K; 25 bool topologicalSort() 26 { 27 fill(minStartTimeVec.begin(), minStartTimeVec.end(), 0); 28 queue<int> q; 29 for(int i = 1; i <= N; ++ i) 30 if(inDegreeVec[i] == 0) 31 q.push(i); 32 while(!q.empty()){ 33 int u = q.front(); 34 q.pop(); 35 topologicalStack.push(u); 36 for(auto it = vexEdgeVec[u].begin(); it != vexEdgeVec[u].end(); ++it){ 37 inDegreeVec[it->v] --; 38 if(inDegreeVec[it->v] == 0) 39 q.push(it->v); 40 if(minStartTimeVec[it->v] < minStartTimeVec[u] + it->w) 41 minStartTimeVec[it->v] = minStartTimeVec[u] + it->w; 42 } 43 } 44 if(topologicalStack.size() == N) 45 return true; 46 else 47 return false; 48 } 49 int criticalPath() 50 { 51 int maxLen = -1; 52 if(!topologicalSort()) 53 return -1; 54 //多个汇点 找最大时间 55 for(int i = 1; i <= N; ++ i) 56 if(minStartTimeVec[i] > maxLen) 57 maxLen = minStartTimeVec[i]; 58 fill(maxEndTimeVec.begin(), maxEndTimeVec.end(), maxLen); 59 while(!topologicalStack.empty()){ 60 int u = topologicalStack.top(); 61 topologicalStack.pop(); 62 for(auto it = vexEdgeVec[u].begin(); it != vexEdgeVec[u].end(); ++ it) 63 if(maxEndTimeVec[it->v] - it->w < maxEndTimeVec[u]) 64 maxEndTimeVec[u] = maxEndTimeVec[it->v] - it->w; 65 } 66 for(int u = 1; u <= N; ++ u) 67 for(auto it = vexEdgeVec[u].begin(); it != vexEdgeVec[u].end(); ++it){ 68 e[u][it->v] = minStartTimeVec[u]; 69 l[u][it->v] = maxEndTimeVec[it->v] - it->w; 70 if(e[u][it->v] == l[u][it->v] ) 71 criticalPathPreVec[u].push_back(it->v); 72 } 73 return maxLen; 74 } 75 void dfs(int u) 76 { 77 if(criticalPathPreVec[u].size() == 0) 78 { 79 for(int i = 0; i < tmpPathVec.size(); ++ i) 80 { 81 if(i > 0) 82 printf("->"); 83 printf("%d", tmpPathVec[i]); 84 } 85 printf("\n"); 86 return; 87 } 88 sort(criticalPathPreVec[u].begin(), criticalPathPreVec[u].end()); 89 for(auto it = criticalPathPreVec[u].begin(); it != criticalPathPreVec[u].end(); ++it) 90 { 91 tmpPathVec.push_back(*it); 92 dfs(*it); 93 tmpPathVec.pop_back(); 94 } 95 } 96 int main(){ 97 cin >> N >> M; 98 int tmpSt, tmpEnd, tmpW; 99 while(M--){ 100 cin >> tmpSt >> tmpEnd >> tmpW; 101 inDegreeVec[tmpEnd] ++; 102 inDegOriginVec[tmpEnd] ++; 103 vexEdgeVec[tmpSt].push_back(NODE(tmpEnd, tmpW)); 104 } 105 cin >> K; 106 edgeQueryVec.resize(K); 107 for(int i = 0; i < K; ++ i) 108 cin >> edgeQueryVec[i].start >> edgeQueryVec[i].end; 109 int criticalLen = criticalPath(); 110 if(criticalLen == -1){ 111 cout << "NO" << endl; 112 return 0; 113 } 114 cout << "YES" << endl; 115 for(auto it = edgeQueryVec.begin(); it != edgeQueryVec.end(); ++ it) 116 printf("%d %d\n", e[it->start][it->end], l[it->start][it->end]); 117 cout << criticalLen << endl; 118 for(int i = 1; i <= N; ++i) 119 if(inDegOriginVec[i] == 0 && criticalPathPreVec[i].size() != 0)//是源点且不是单独的点 120 { 121 tmpPathVec.push_back(i); 122 dfs(i); 123 tmpPathVec.pop_back(); 124 } 125 return 0; 126 }
NO
Author
Shoutmon
Source
19浙大考研机试模拟赛
这道题目感觉挺有价值的,题目考察如下:
1.拓扑排序。通过拓扑排序判断所给图是不是有向无环图, 同时找出每个点的最早发生时间。(考虑从多个源点开始拓扑)
2.逆向拓扑。根据拓扑的顺序,反向找出每个点的最迟发生时间。
3.最长时间。遍历所有点的最早发生时间找到最长的时间(考虑多个汇点)。
4.关键路径。当前点u的最早开始时间 等于 后一个点v的最晚开始时间减去u->v所用的时间时,该路径为关键路径,邻接表进行存储。
5.DFS。遍历所有关键路径,按照要求输出。