将所有节点排序,使得排在前面的节点不能依赖于排在后面的节点。它的思想是,每次取出图上不被依赖的点,同时删去与这些点相连的边,更新图上的依赖关系,直到没有点可以被取出。

拓扑排序也用于发现图上的环,这些节点相互依赖,不会出现在排序结果当中。

  1. #include <iostream>
  2. #include <queue>
  3. #include <vector>
  4. #include <algorithm>
  5. #include <cstring>
  6. using namespace std;
  7. const int N = 10004;
  8. vector<int> g[N];
  9. vector<int> ans;
  10. int indegree[N];
  11. int n, m;
  12. bool TopologicalSort() {
  13. queue<int> q;
  14. for (int i=1; i<=n; ++i) {
  15. if (indegree[i] == 0) { // 入度为 0 的节点不被依赖
  16. q.push(i);
  17. ans.push_back(i);
  18. }
  19. }
  20. while (!q.empty()) {
  21. int x = q.front();
  22. q.pop();
  23. for (int i=0; i<g[x].size(); ++i) { // 遍历所有出边的终点
  24. int y = g[x][i];
  25. if (--indegree[y] == 0) { // 删除边,使终点入度减 1
  26. q.push(y); // 入度为 0 的节点不被依赖
  27. ans.push_back(y);
  28. }
  29. }
  30. }
  31. return ans.size() == n;
  32. }
  33. int main() {
  34. cin >> n >> m;
  35. for (int i=0; i<m; ++i) {
  36. int x, y;
  37. cin >> x >> y;
  38. g[x].push_back(y);
  39. ++indegree[y]; // 有向图
  40. }
  41. if (TopologicalSort()) {
  42. for (int i=0; i<n; ++i) {
  43. cout << ans[i] << endl;
  44. }
  45. } else {
  46. cout << "Cycle deteted." << endl;
  47. }
  48. return 0;
  49. }

时间复杂度:5.8.5 拓扑排序 - 图1#card=math&code=O%28n%20%2B%20m%29&id=tm5sm),5.8.5 拓扑排序 - 图2 为点数, 5.8.5 拓扑排序 - 图3 为边数

例题:蓝桥 发现环【第八届】【决赛】

用拓扑排序解决发现环的问题再适合不过。题目要求输出环上的点。与模板稍有出入的是,这里的图是一张无向图。在无向图上,我们关于「依赖」的考虑需要稍稍变化——在无向图的环上,所有节点至少与其他两个节点相连,也就是说,它的度保证不小于 2 。如果找到一个节点的度为 1,那么它不在环上。

在经历了最短路的学习后,你应该对这些图的基本操作有一定的了解,可以自如地调整模板。

参考代码
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int N = 100004;
vector<int> g[N];
int deg[N];
bool vis[N];
int n;
void toposort() {
    queue<int> q;
    for (int i=1; i<=n; ++i) {
        if (deg[i] == 1) {            // 度为 1 的节点不被依赖
            q.push(i);
        }
    }
    while (!q.empty()) {
        int x = q.front();
        q.pop();
        vis[x] = true;
        for (int i=0; i<g[x].size(); ++i) {
            int y = g[x][i];
            if (--deg[y] == 1) {
                q.push(y);            // 度为 1 的节点不被依赖
            }
        }
    }
}
int main() {
    cin >> n;
    for (int i=0; i<n; ++i) {
        int x, y;
        cin >> x >> y;
        g[x].push_back(y);
        g[y].push_back(x);
        ++deg[x];
        ++deg[y];
    }
    toposort();
    bool head = true;
    for (int i=1; i<=n; ++i) {
        if (!vis[i]) {
            if (!head) cout << " ";        // 严谨输出,行末不留空格
            else head = false;
            cout << i;
        }
    }
    cout << endl;
    return 0;
}