文章链接: 拓扑排序精讲 dijkstra(朴素版)精讲

题目链接: 117. 软件构建 47. 参加科学大会


拓扑排序精讲

拓扑排序的定义:

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

(当然拓扑排序也要检测这个有向图 是否有环,即存在循环依赖的情况,因为这种情况是不能做线性排序的。

所以拓扑排序也是图论中判断有向无环图的常用方法

思路:

第一步:找到入度为0 的节点,加入结果集;

第二步:将该节点从图中移除。

循环以上两步,直到所有节点都在图中被移除了。

【结果集的顺序,就是我们想要的拓扑排序顺序 (结果集里顺序可能不唯一)。】


#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>
using namespace std;

int main() {
    int m, n, s, t;
    cin >> n >> m;
    vector<int> inDegree(n, 0); // 记录每个点的入度
    unordered_map<int, vector<int>> umap; // 记录文件的依赖关系(谁指向谁)
    vector<int> result;
    
    while (m--) { // 记录s->t
        cin >> s >> t;
        inDegree[t]++; // // t的入度加一
        umap[s].push_back(t); // // 记录s指向哪些文件
    }
    
    queue<int> que; // BFS
    for (int i = 0; i < n; i++) {
        if (inDegree[i] == 0) que.push(i); // 将入度为0的加入队列
    }
    
    while (que.size()) {
        int cur = que.front();
        que.pop();
        result.push_back(cur); // 入度为0的放入结果集
        vector<int> files = umap[cur]; // 获得该文件指向的文件
        if (files.size()) {
            for (int i = 0; i < files.size(); i++) {
                inDegree[files[i]]--;
                if (inDegree[files[i]] == 0) { // 将入度为0的加入队列
                    que.push(files[i]);
                }
            }
        }
    }
    
    if (result.size() == n) {
        for (int i = 0; i < n - 1; i++) {
            cout << result[i] << " ";
        }
        cout << result[n - 1];
    } else {
        cout << -1 << '\n';
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.


dijkstra(朴素版)精讲

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

dijkstra三部曲:

第一步,选源点到哪个节点近且该节点未被访问过;

第二步,该最近节点被标记访问过;

第三步,更新非访问节点到源点的距离(即更新minDist数组)。


#include <iostream>
#include <vector>
#include <climits>
using namespace std;

int main() {
    int n, m, p1, p2, val;
    cin >> n >> m;
    vector<vector<int>> grid(n + 1, vector<int>(n + 1, INT_MAX));
    for (int i = 0; i < m; i++) { // 记录图
        cin >> p1 >> p2 >> val;
        grid[p1][p2] = val;
    }
    
    int start = 1;
    int end = n;
    vector<int> minDist(n + 1, INT_MAX); // 记录源点到每个节点的最短距离
    vector<bool> visited(n + 1, false); // 记录点是否被访问过
    minDist[start] = 0;
    
    for (int i = 1; i <= n; i++) {
        int minVal = INT_MAX;
        int cur = 1;
        
        // 1.选距离源点最近且未访问过的节点
        for (int v = 1; v <= n; v++) {
            if (!visited[v] && minDist[v] < minVal) {
                minVal = minDist[v];
                cur = v;
            }
        }
        
        // 2.标记该节点已被访问
        visited[cur] = true;
        
        // 3.更新minDist数组
        for (int v = 1; v <= n; v++) {
            if (!visited[v] && grid[cur][v] != INT_MAX && minDist[cur] + grid[cur][v] < minDist[v]) {
                minDist[v] = minDist[cur] + grid[cur][v];
            }
        }
    }
    
    if (minDist[end] == INT_MAX) {
        cout << -1 << '\n';
    } else {
        cout  << minDist[end] << '\n';
    }
    
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.