📜  Dijkstra 和 Floyd-Warshall 算法的比较(1)

📅  最后修改于: 2023-12-03 14:40:43.805000             🧑  作者: Mango

Dijkstra 和 Floyd-Warshall 算法的比较

Dijkstra 和 Floyd-Warshall 算法都是最短路径算法,但它们的具体实现方式和适用场景有所不同。

Dijkstra 算法
原理

Dijkstra 算法采用贪心策略,从起点开始,每次选择当前距离起点最近的一个顶点,然后以该顶点为中心,更新与它直接相连的顶点的距离。不断重复这个过程,直到所有顶点的最短距离都被计算出来。

优点

Dijkstra 算法对于稠密图的效率比较高,因为它只计算与当前顶点相邻的顶点,而不会对所有的顶点都进行计算。

缺点

Dijkstra 算法只能处理边权非负的图,否则会出现负权回路的情况。此外,每次选择最近的顶点后,需要更新与它直接相连的所有顶点,这个过程比较耗时,因此在稀疏图中比较慢。

代码片段
// 给定起点 s 和图 G,返回起点到所有顶点的最短路径
vector<int> dijkstra(int s, vector<vector<pair<int, int>>>& G) {
    int n = G.size();
    vector<int> dist(n, INT_MAX / 2);  // 到每个顶点的最短距离
    vector<bool> used(n, false);      // 是否已经访问过
    dist[s] = 0;
    while (true) {
        int v = -1;
        for (int u = 0; u < n; ++u) {
            if (!used[u] && (v == -1 || dist[u] < dist[v])) {
                v = u;
            }
        }
        if (v == -1) {
            break;
        }
        used[v] = true;
        for (auto e : G[v]) {
            int u = e.first;
            int w = e.second;
            if (dist[v] + w < dist[u]) {
                dist[u] = dist[v] + w;
            }
        }
    }
    return dist;
}
Floyd-Warshall 算法
原理

Floyd-Warshall 算法采用动态规划的思想,它的核心思想是利用中间节点的信息来更新起点到终点的距离。对于每一对顶点 u 和 v,算法维护一个矩阵 D,其中 D[u][v] 表示从 u 到 v 的最短距离。算法的主要思想是,对于任意的中间节点 k,如果从 u 到 v 的距离要经过节点 k,那么可以在已知的 D[u][k] 和 D[k][v] 基础上计算出 D[u][v]。

优点

Floyd-Warshall 算法可以处理边权为负的图,而且比较适合稠密图,因为它的复杂度为 O(n^3)。

缺点

Floyd-Warshall 算法的时间复杂度为 O(n^3),在稀疏图中比较慢,此外,它需要维护一个矩阵,空间复杂度也比较高。

代码片段
// 计算任意两个顶点之间的最短距离
vector<vector<int>> floyd_warshall(vector<vector<int>>& G) {
    int n = G.size();
    vector<vector<int>> dist(n, vector<int>(n, INT_MAX / 2));
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            if (i == j) {
                dist[i][j] = 0;  // 自己到自己的距离为 0
            } else if (G[i][j] != -1) { // 有边相连
                dist[i][j] = G[i][j];
            }
        }
    }
    for (int k = 0; k < n; ++k) {
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (dist[i][k] != INT_MAX / 2 && dist[k][j] != INT_MAX / 2) {
                    dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
                }
            }
        }
    }
    return dist;
}
总结

Dijkstra 算法适合稠密图或者边权非负的情况,而 Floyd-Warshall 算法适合稠密图或者边权带负数的情况。对于稀疏图,可以采用 Bellman-Ford 算法来求解最短路径。