拓扑排序
介绍
拓扑排序是一种将一个有向无环图变成一个线性序列的算法。
这个序列的要求是:
- 每个顶点都出现了一次。
- 对于一条边:,我们要求 在 的前面。
实现
- 找到入度为 的点,输出。
- 删除这个点和这个点连着的所有边。
- 继续重复前两步,直到没有点了。
代码
B3644 【模板】拓扑排序 / 家谱树 – 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include <bits/stdc++.h> using namespace std; /* */ int n; vector <int> v[100005], v2[100005]; int d[100005]; int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n; for (int i = 1; i <= n; i ++) { int x; while (cin >> x) { if (x == 0) break; else v[x].push_back(i), d[x] ++, v2[i].push_back(x); } } queue <int> q; for (int i = 1; i <= n; i ++) { if (v[i].size() == 0) { cout << i << " "; q.push(i); } } // cout << "*\n" << v2[q.front()].size(); while (q.size()) { int x = q.front(); q.pop(); for (int i = 0; i < v2[x].size(); i ++) { d[v2[x][i]] --; // cout << d[v[x][i]] << " "; if (d[v2[x][i]] == 0) { cout << v2[x][i] << " "; q.push(v2[x][i]); } } } return 0; }
关键路径
介绍
我们把一个有向无环图想象成一个工程的规划图,必须在完成前一项后才能完成后一项,二千每一个没有关联的项可以同时开工。
关键路径,就是如果增加关键路径中任意一项的时间的话,整个工程的时间就会增加。
实现
关键路径其实就是从入度为 的一个点到出度为 的一个点的最长路径。
我们可以定义两个数组,一个数组存储从入度为 的起点到其他点的最短用时;一个数组存储从出度为 的一个点到其他点的最长时间。
具体实现见代码。
如果一个点的最短时间和最长时间是一样的,那么这个点就在关键路径里面。
代码
#include <bits/stdc++.h> using namespace std; int a[105][105], e[1005], l[1005], n, in[1005], ou[1005]; vector <int> ed[1005], v[1005], v2[1005], ed2[1005]; int s = 0, t = 0; int main() { cin >> n; for (int i = 1; i <= n; i ++) { for (int j = 1; j <= n; j ++) { cin >> a[i][j]; if (a[i][j] == 0) continue; ed[i].push_back(j); ed2[j].push_back(i); v[i].push_back(a[i][j]); v2[j].push_back(a[i][j]); in[j] ++, ou[i] ++; } } for (int i = 1; i <= n; i ++) { // cout << in[i] << " " << ou[i] << "\n"; if (in[i] == 0) ed[0].push_back(i), s = i; if (ou[i] == 0) ed[n + 1].push_back(i), t = i; } queue <int> q; q.push(s); while (q.size()) { int nw = q.front(); q.pop(); // cout << nw << " "; for (int i = 0; i < ed[nw].size(); i ++) { e[ed[nw][i]] = max(e[ed[nw][i]], e[nw] + v[nw][i]); in[ed[nw][i]] --; // cout << e[ed[nw][i]] << ' ' << in[e[ed[nw][i]]] << "\n"; if (in[ed[nw][i]] == 0) { q.push(ed[nw][i]); } } } q.push(t); for (int i = 1; i <= n; i ++) l[i] = e[t]; while (q.size()) { int nw = q.front(); q.pop(); // cout << ed2[nw].size(); for (int i = 0; i < ed2[nw].size(); i ++) { l[ed2[nw][i]] = min(l[ed2[nw][i]], l[nw] - v2[nw][i]); ou[ed2[nw][i]] --; // cout << 114514 << "\n"; if (ou[ed2[nw][i]] == 0) { q.push(ed2[nw][i]); } } } for (int i = 1; i <= n; i ++) { // cout << e[i] << " " << l[i] << "\n"; if (e[i] == l[i]) cout << i << " "; } }