关键路径
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。遍历所有关键路径,按照要求输出。
