1044 关键路径 (浙大机试模拟)

自闭症网瘾萝莉.ら 提交于 2019-11-29 06:24:18

关键路径

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 }
View Code

 

NO

Author

Shoutmon

Source

19浙大考研机试模拟赛
 
 
这道题目感觉挺有价值的,题目考察如下:
1.拓扑排序。通过拓扑排序判断所给图是不是有向无环图, 同时找出每个点的最早发生时间。(考虑从多个源点开始拓扑)
2.逆向拓扑。根据拓扑的顺序,反向找出每个点的最迟发生时间
3.最长时间。遍历所有点的最早发生时间找到最长的时间(考虑多个汇点)。
4.关键路径。当前点u的最早开始时间 等于 后一个点v的最晚开始时间减去u->v所用的时间时,该路径为关键路径,邻接表进行存储。
5.DFS。遍历所有关键路径,按照要求输出。
 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!