图论---拓扑排序(DFS)

  1. 时间复杂度:

    • 最坏情况下为O(V!),其中V是顶点数

    • 实际运行时间取决于图的拓扑结构

这个实现可以输出有向无环图的所有可能的拓扑排序,并能检测图中是否存在环。

  1. 算法思想:

    • 使用回溯法枚举所有可能的拓扑排序

    • 在每一步选择当前入度为0的顶点,递归处理剩余顶点

    • 回溯时恢复入度和访问状态

  2. 关键数据结构:

    • inDegree:记录每个顶点的当前入度

    • visited:标记顶点是否已被访问

    • currentOrder:存储当前正在构建的拓扑排序

    • allOrders:存储所有找到的拓扑排序

  3. 环检测:

    如果无法找到任何拓扑排序(allOrders为空),说明图中存在环

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

vector<vector<int>> graph;
vector<int> inDegree;
vector<bool> visited;
vector<int> currentOrder;
vector<vector<int>> allOrders;
void allTopSortUtil(int n) {
    // 标志变量,表示是否找到了一个有效的顶点
    bool flag = false;

    for (int u = 0; u < n; u++) {
        // 选择一个入度为0且未被访问的顶点
        if (inDegree[u] == 0 && !visited[u]) {
            // 减少所有邻接顶点的入度
            for (int v : graph[u]) {
                inDegree[v]--;
            }
            // 将当前顶点加入结果并标记为已访问
            currentOrder.push_back(u);
            visited[u] = true;
            // 递归处理剩余顶点
            allTopSortUtil(n);
            // 回溯:重置访问标记和入度
            visited[u] = false;
            currentOrder.pop_back();
            for (int v : graph[u]) {
                inDegree[v]++;
            }
            flag = true;
        }
    }

    // 如果没有顶点可选,说明已经得到一个完整的拓扑排序
    if (!flag) {
        if ((int)currentOrder.size() == n) {
            allOrders.push_back(currentOrder);
        }
    }
}

vector<vector<int>> allTopSorts(int n) {
    vector<int> inDegree(n, 0);
    vector<bool> visited(n, false);
    // 计算每个顶点的入度
    for (int u = 0; u < n; u++) {
        for (int v : graph[u]) {
            inDegree[v]++;
        }
    }
    allTopSortUtil(n);
    return allOrders;
}

int main() {
    // 示例:构建一个有向无环图
    int n = 6;  // 节点数量
    vector<vector<int>> graph(n);

    // 添加边
    graph[5].push_back(2);
    graph[5].push_back(0);
    graph[4].push_back(0);
    graph[4].push_back(1);
    graph[2].push_back(3);
    graph[3].push_back(1);

    // 获取所有可能的拓扑排序
    vector<vector<int>> allOrders = allTopSorts(n);

    // 输出结果
    if (allOrders.empty()) {
        cout << "图中存在环,无法进行拓扑排序!" << endl;
    } else {
        cout << "所有可能的拓扑排序:" << endl;
        for (auto& order : allOrders) {
            for (int node : order) {
                cout << node << " ";
            }
            cout << endl;
        }
        cout << "共找到 " << allOrders.size() << " 种拓扑排序" << endl;
    }

    return 0;
}
相关推荐
yi01116 分钟前
LeetCode 3. 无重复字符的最长子串|不定长滑动窗口:什么时候更新最大值?
笔记·python·算法·leetcode·双指针·滑动窗口
y1su23 分钟前
Leetcode 单调栈模板
java·开发语言·数据结构·算法·leetcode
索尔~古德曼38 分钟前
CF(1400-1400&1300-1500)
算法
爱刷碗的苏泓舒1 小时前
泰勒级数与泰勒展开:GNSS卫地距线性化、Jacobian矩阵与Hessian矩阵
线性代数·算法·矩阵·gnss·雅可比矩阵·卫地距线性化·海森矩阵
垆边人似月.1 小时前
华为题:每日温度
数据结构·c++·算法
Sylvia-girl1 小时前
堆排序算法
算法·排序算法·c
Peregrine91 小时前
数据结构 - > 树和二叉树
数据结构·算法
我是人✓1 小时前
Java面向对象核心特性深度解析
java·前端·算法
j7~1 小时前
【算法】专题四.前缀和:一维二维模板,配套 LeetCode 真题,结合同余定理、哈希前缀和,搞定子数组与子矩阵区间求和问题。
数据结构·c++·算法·前缀和·优选算法
看浪的路人1 小时前
第1讲:2026 大模型应用开发全景——Prompt / RAG / 微调 / Agent 到底先用哪个
人工智能·算法