算法 之 拓 扑 排 序

文章目录

拓扑排序

  • 拓扑排序,常用于这个课程表安排类型的,对于一个抽象为一个有向无环图,经过排序之后,排序之后的元素x,y,仍然保持着在原来的有向无环图当中,x->y,也就是前后的顺序仍然不变

灵神讲解

  • 讲一下拓扑排序的思路:
    • 首先输入的是一个边的关系edges[i] = [x,y]表示,存在x->y的有向边,我们需要将这个边,使用邻接表存储起来,同时还使用一个数组存储每一个顶点的入度数量
    • 使用一个队列来存储候选将要拓展的节点,当然一开始,加入队列的元素就是入度为0的节点
    • 选取队列中的元素,加入最终的排序的数组中,同时,对于以该元素作为起始节点的边所对应的节点的入度数量应该-1,同时判断,将新的入度数量为0的节点加入候选队列当中
    • 如果最终,排序的元素数量少于总的节点数量,则说明存在环
cpp 复制代码
// 返回有向无环图(DAG)的其中一个拓扑序
// 如果图中有环,返回空列表
// 节点编号从 0 到 n-1
vector<int> topologicalSort(int n, vector<vector<int>>& edges) {
    vector<vector<int>> g(n);
    vector<int> in_deg(n);
    for (auto& e : edges) {
        int x = e[0], y = e[1];
        g[x].push_back(y);
        in_deg[y]++; // 统计 y 的先修课数量
    }

    queue<int> q;
    for (int i = 0; i < n; i++) {
        if (in_deg[i] == 0) { // 没有先修课,可以直接上
            q.push(i); // 加入学习队列
        }
    }

    vector<int> topo_order;
    while (!q.empty()) {
        int x = q.front();
        q.pop();
        topo_order.push_back(x);
        for (int y : g[x]) {
            in_deg[y]--; // 修完 x 后,y 的先修课数量减一
            if (in_deg[y] == 0) { // y 的先修课全部上完
                q.push(y); // 加入学习队列
            }
        }
    }

    if (topo_order.size() < n) { // 图中有环
        return {};
    }
    return topo_order;
}

拓扑排序+dp解决工程完成时间

  • 拓扑排序,适合处理有向无环图当中,解决活动先后顺序的安排,当然,我们也可以计算出完成全部的活动所需的最少时间
  • 我们定义dp[i]为完成任务i的最早完成时间,那么就有递推公式dp[i] = max(dp[j) +time[i],其中dp[j]j->i的节点

2050.并行课程 III

  • 思路分析:
    • 解决的方法,也就是在出候选队列的时候,我们在更新入度节点的时候,同时更新这个dp[i]即可
cpp 复制代码
class Solution {
public:
    int minimumTime(int n, vector<vector<int>>& relations, vector<int>& time) {
        // 拓扑排序+dp
        vector<int> dp(n+1);
        vector<int> ine(n+1);
        vector<vector<int>> e(n+1);
        queue<int> q;
        for (auto p : relations){
            int u = p[0],v = p[1];
            e[u].push_back(v);
            ine[v]++;
        }
        // 初始化队列
        for (int i = 1; i <= n; i++){
            if (ine[i] == 0){
                q.push(i);
                dp[i] = time[i-1];
            }
        }
        // 开始排序
        while (q.size()){
            int x = q.front();
            q.pop();
            for (auto c : e[x]){
                ine[c]--;
                dp[c] = max(dp[c],dp[x] + time[c-1]);
                if (ine[c] == 0){
                    q.push(c);
                }
            }

        }
        // 遍历完,找到这个最大的dp
        int ans = 0;
        for (int i = 1;i <= n; i++){
            cout << dp[i] << " ";
            ans = max(ans,dp[i]);
        }
        return ans;
    }
};
相关推荐
Tongzhi20267 小时前
通芝科技考勤软件三大发展趋势:AI大模型、无感识别与数据底座
大数据·科技·算法·爬山算法
eBest数字化转型方案7 小时前
Route Optimization for FMCG:多目标排线算法的工程实现
大数据·人工智能·算法
洋不写bug8 小时前
链表补充练习,双链表的模拟实现
java·数据结构·链表·双链表·底层实现
residual_fan8 小时前
持续对比强化学习(Continual Contrastive Reinforcement Learning)论文分享
人工智能·算法·数据挖掘·数据分析
s_w.h8 小时前
【 计网 】序列化与反序列化
linux·服务器·网络·算法·bash
信奥卷王8 小时前
2025年09月GESPC++五级真题解析(含视频)
算法
白狐_7988 小时前
408 数据结构|外部排序:流程与 k 路归并
数据结构·算法
闻缺陷则喜何志丹8 小时前
【动态规划】P3609 [USACO17JAN] Hoof, Paper, Scissor G
c++·算法·动态规划·洛谷
leihefeng9 小时前
手写数字识别:KNN vs 逻辑回归实战
python·算法·机器学习·逻辑回归·scikit-learn
全栈技术负责人10 小时前
DeepSeek Harness 业务工具权限插件 dsh-tool-permission设计思路
网络·算法·ai·ai编程