• 图论篇--代码随想录算法训练营第五十八天打卡|拓扑排序,dijkstra(朴素版),dijkstra(堆优化版)精讲


    拓扑排序

    题目链接:117. 软件构建

    题目描述:

    某个大型软件项目的构建系统拥有 N 个文件,文件编号从 0 到 N - 1,在这些文件中,某些文件依赖于其他文件的内容,这意味着如果文件 A 依赖于文件 B,则必须在处理文件 A 之前处理文件 B (0 <= A, B <= N - 1)。请编写一个算法,用于确定文件处理的顺序。

    算法思路:

    拓扑排序:给出一个 有向图,把这个有向图转成线性的排序 

    拓扑排序的过程:

    1. 找到入度为0 的节点,加入结果集
    2. 将该节点从图中移除

    代码:

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. int main() {
    7. int m, n, s, t;
    8. cin >> n >> m;
    9. vector<int> inDegree(n, 0); // 记录每个文件的入度
    10. unordered_map<int, vector<int>> umap;// 记录文件依赖关系
    11. vector<int> result; // 记录结果
    12. while (m--) {
    13. // s->t,先有s才能有t
    14. cin >> s >> t;
    15. inDegree[t]++; // t的入度加一
    16. umap[s].push_back(t); // 记录s指向哪些文件
    17. }
    18. queue<int> que;
    19. for (int i = 0; i < n; i++) {
    20. // 入度为0的文件,可以作为开头,先加入队列
    21. if (inDegree[i] == 0) que.push(i);
    22. //cout << inDegree[i] << endl;
    23. }
    24. // int count = 0;
    25. while (que.size()) {
    26. int cur = que.front(); // 当前选中的文件
    27. que.pop();
    28. //count++;
    29. result.push_back(cur);
    30. vector<int> files = umap[cur]; //获取该文件指向的文件
    31. if (files.size()) { // cur有后续文件
    32. for (int i = 0; i < files.size(); i++) {
    33. inDegree[files[i]] --; // cur的指向的文件入度-1
    34. if(inDegree[files[i]] == 0) que.push(files[i]);
    35. }
    36. }
    37. }
    38. if (result.size() == n) {
    39. for (int i = 0; i < n - 1; i++) cout << result[i] << " ";
    40. cout << result[n - 1];
    41. } else cout << -1 << endl;
    42. }

    dijkstra(朴素版)

    题目链接:47. 参加科学大会(第六期模拟笔试)

    题目描述:

    小明是一位科学家,他需要参加一场重要的国际科学大会,以展示自己的最新研究成果。

    小明的起点是第一个车站,终点是最后一个车站。然而,途中的各个车站之间的道路状况、交通拥堵程度以及可能的自然因素(如天气变化)等不同,这些因素都会影响每条路径的通行时间。

    小明希望能选择一条花费时间最少的路线,以确保他能够尽快到达目的地。

    算法思路:

    dijkstra算法:在有权图(权值非负数)中求从起点到其他节点的最短路径算法。

    需要注意两点:

    • dijkstra 算法可以同时求 起点到所有节点的最短路径
    • 权值不能为负数

    dijkstra三部曲

    1. 第一步,选源点到哪个节点近且该节点未被访问过
    2. 第二步,该最近节点被标记访问过
    3. 第三步,更新非访问节点到源点的距离(即更新minDist数组)

    minDist数组 用来记录 每一个节点距离源点的最小距离

    代码:

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. int main() {
    6. int n, m, p1, p2, val;
    7. cin >> n >> m;
    8. vectorint>> grid(n + 1, vector<int>(n + 1, INT_MAX));
    9. for(int i = 0; i < m; i++){
    10. cin >> p1 >> p2 >> val;
    11. grid[p1][p2] = val;
    12. }
    13. int start = 1;
    14. int end = n;
    15. // 存储从源点到每个节点的最短距离
    16. std::vector<int> minDist(n + 1, INT_MAX);
    17. // 记录顶点是否被访问过
    18. std::vector<bool> visited(n + 1, false);
    19. minDist[start] = 0; // 起始点到自身的距离为0
    20. for (int i = 1; i <= n; i++) { // 遍历所有节点
    21. int minVal = INT_MAX;
    22. int cur = 1;
    23. // 1、选距离源点最近且未访问过的节点
    24. for (int v = 1; v <= n; ++v) {
    25. if (!visited[v] && minDist[v] < minVal) {
    26. minVal = minDist[v];
    27. cur = v;
    28. }
    29. }
    30. visited[cur] = true; // 2、标记该节点已被访问
    31. // 3、第三步,更新非访问节点到源点的距离(即更新minDist数组)
    32. for (int v = 1; v <= n; v++) {
    33. if (!visited[v] && grid[cur][v] != INT_MAX && minDist[cur] + grid[cur][v] < minDist[v]) {
    34. minDist[v] = minDist[cur] + grid[cur][v];
    35. }
    36. }
    37. }
    38. if (minDist[end] == INT_MAX) cout << -1 << endl; // 不能到达终点
    39. else cout << minDist[end] << endl; // 到达终点最短路径
    40. }

    dijkstra(堆优化版)精讲

    算法思路: 

    朴素版考虑点,堆优化版考虑边(类似于prim和kruskal算法)

    1、使用邻接表存图信息<节点,权值>

    2、dijkstra 三部曲:

    1. 第一步,选源点到哪个节点近且该节点未被访问过-->使用一个 小顶堆 来帮我们对边的权值排序,每次从小顶堆堆顶 取边就是权值最小的边。
    2. 第二步,该最近节点被标记访问过。-->同朴素版
    3. 第三步,更新非访问节点到源点的距离(即更新minDist数组)-->遍历该节点在邻接表中所指向的一系列节点,若之前为访问过,则入堆。

     

  • 相关阅读:
    K8S之Ingress 对外暴露应用(十四)
    MyBatis完成增删改查案例(详细代码)
    运动哪种耳机好用,推荐五款适合运动的耳机分享
    【openSSH】通过证书文件免密码远程登录
    c++模板进阶
    app备案
    线代9讲 第6讲
    Ansible
    【每日一题】—— C. Yarik and Array(Codeforces Round 909 (Div. 3))(贪心)
    计算机基础学习(好文必看)
  • 原文地址:https://blog.csdn.net/m0_67804957/article/details/142183410