拓扑排序不同于普通排序,普通排序就是按照某一规则对具有同类性质的元素进行升序或降序排序;而拓扑排序是针对有向无环图(Directed Acyclic Graph,DAG)G 进行的,是将图 G 中所有顶点排成一个线性序列,使得图中任意一对顶点 u 和 v,若边 $<u, v>$是图 G 的边(也即存在一条 u 到 v 的有向路径),则 u 在线性序列中一定出现在 v 之前,这样的序列叫做拓扑序列,而这个得到这个序列的过程就叫做拓扑排序。
这道题没啥说的,就是关键路径的问题。相比上道题,这道题要麻烦一些,因为这个题不仅要输出最早完成时间,还得输出关键路径,多亏了 STL 省了很多麻烦。 求最早完成时间的思路与上面那题是一样的,直接一个拓扑排序就完事了。难点在于如何找关键路径,不能简单的直接拿拓扑序列来反向输出,那怎么办呢? 仔细回忆一下课上的例子,可以发现关键路径的关键活动没有空余时间,假如 e 是活动的最早完成时间,l 是活动的最晚开始时间,那么关键活动的 e 与 l 是相等。按照这样的思路,将拓扑序列中的所有的关键活动的 e 和 l 求出,并进行比较,如果相等,就是关键活动了,当然了,前提是拓扑序列是存在的。 但是别忘记了,题目要求从小到大输出关键活动,所以还需要对找出的序列进行排序,然后再输出。
#include<iostream> #include<vector> #include<queue> #include<stack> #include<algorithm> usingnamespace std; constint maxn = 100 + 5; constint inf = 0x3fffffff; structnode { int v, w; node(int v, int w) { this->v = v; this->w = w; } }; boolcmp(int a, int b){ return b - a; } vector<node> G[maxn]; stack<int> topo; int nv, ne, ve[maxn] = { 0 }, vl[maxn], indegree[maxn] = { 0 }; booltopoorder(){ queue<int> q; for (int i = 1; i <= nv; i++) { for (int j = 0; j < G[i].size(); j++) { indegree[G[i][j].v]++; } } for (int i = 1; i <= nv; i++) { if (indegree[i] == 0) { q.push(i); ve[i] = 0; } } while (!q.empty()) { int u = q.front(); topo.push(u); q.pop(); for (int i = 0; i < G[u].size(); i++) { indegree[G[u][i].v]--; if (ve[G[u][i].v] < ve[u] + G[u][i].w) { ve[G[u][i].v] = ve[u] + G[u][i].w; } if (indegree[G[u][i].v] == 0) q.push(G[u][i].v); } } if (topo.size() != nv) returnfalse; elsereturntrue; } voidcriticalpath(){ int max = ve[1], maxid = 1; for (int i = 2; i <= nv; i++) { if (ve[i] > max) { max = ve[i]; maxid = i; } } cout << max << endl; for (int i = 0; i < maxn; i++) vl[i] = max; while (!topo.empty()) { int u = topo.top(); topo.pop(); for (int i = 0; i < G[u].size(); i++) { int v = G[u][i].v; if (vl[v] - G[u][i].w < vl[u]) { vl[u] = vl[v] - G[u][i].w; } } } vector<int> keyact[maxn]; for (int u = 1; u <= nv; u++) { for (int i = 0; i < G[u].size(); i++) { int v = G[u][i].v, w = G[u][i].w; int e = ve[u], l = vl[v] - w; if (e == l) keyact[u].push_back(v); } } for (int i = 1; i <= nv; i++) sort(keyact[i].begin(), keyact[i].end(), cmp); for (int u = 1; u <= nv; u++) { for (int i = 0; i < keyact[u].size(); i++) { cout << u << "->" << keyact[u][i] << endl; } } } intmain(){ cin >> nv >> ne; int u, v, w; for (int i = 0; i < ne; i++) { cin >> u >> v >> w; G[u].emplace_back(v, w); } if (!topoorder()) cout << 0; elsecriticalpath(); return0; }