最短路径算法

最短路径算法是图论中的核心内容,用于在加权图中寻找两个节点之间路径权值之和最小的路径。根据不同的应用场景,最短路径算法可以分为多种类型。

一、算法分类与特点

1. 单源最短路径算法(从一个固定起点出发)

Dijkstra算法

  • 适用条件:边权非负的有向图或无向图
  • 时间复杂度:
    • 基础实现:O(V2)
    • 优先队列优化:O((V+E) log V)
    • 斐波那契堆优化:O(V log V + E)
  • 核心思想:贪心策略,每次选择当前未访问节点中距离起点最近的节点

Bellman-Ford算法

  • 适用条件:允许负权边,但不能有负权环
  • 时间复杂度:O(VE)
  • 特点:可以检测负权环

SPFA算法

  • 适用条件:允许负权边,但不能有负权环
  • 时间复杂度:平均O(E),最坏O(V E)
  • 特点:Bellman-Ford的队列优化版本

2. 多源最短路径算法(任意两点间)

Floyd-Warshall算法

  • 适用条件:任意权值图(可处理负权边)
  • 时间复杂度:O(V3)
  • 空间复杂度:O(V2)
  • 特点:动态规划思想,代码简洁

二、算法详细解析

Dijkstra算法实现(C++优先队列版)

typedef pair<int, int> pii;

vector<int> dijkstra(vector<vector<pii>>& graph, int start) {
    int n = graph.size();
    vector<int> dist(n, INT_MAX);
    priority_queue<pii, vector<pii>, greater<pii>> pq;

    dist[start] = 0;
    pq.push({0, start});

    while (!pq.empty()) {
        auto [d, u] = pq.top(); pq.pop();
        if (d > dist[u]) continue;

        for (auto [v, w] : graph[u]) {
            if (dist[v] > dist[u] + w) {
                dist[v] = dist[u] + w;
                pq.push({dist[v], v});
            }
        }
    }
    return dist;
}

Floyd算法实现(C++版)

void floyd(vector<vector<int>>& dist) {
    int n = dist.size();
    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 && dist[k][j] != INT_MAX)
                    dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}

三、算法选择指南

场景推荐算法原因
非负权图,单源Dijkstra效率高
含负权边,单源Bellman-Ford/SPFA能处理负权
多源最短路径Floyd-Warshall直接计算所有点对
稀疏图SPFA平均效率高
稠密图Dijkstra更稳定

四、典型应用场景

  1. 地图导航:计算两点间最短行车路线(Dijkstra)
  2. 网络路由:寻找最优数据传输路径(Bellman-Ford)
  3. 交通规划:计算所有地点间的最短距离(Floyd)
  4. 游戏AI:寻路算法(A*算法,Dijkstra变种)
  5. 社交网络:计算人与人之间的”距离”(广度优先搜索)
滚动至顶部