📜  最短路径更快算法(1)

📅  最后修改于: 2023-12-03 15:10:37.254000             🧑  作者: Mango

最短路径更快算法

最短路径问题是计算在加权图中从一个顶点到另一个顶点的最短路径的问题。这个问题可能有多个解决方案,包括 Dijkstra 算法、Bellman-Ford 算法以及 Floyd Warshall 算法等等。这些算法都是基于图的权重来计算最短路径。

Dijkstra 算法

Dijkstra 算法是解决单源最短路径问题的经典算法。该算法是基于贪心策略的,每次选择距离源点最近的一个顶点进行扩展,直到扩展到目标点为止。

Dijkstra 算法的时间复杂度为 O(|V|^2),其中 |V| 表示顶点数。如果使用优先队列来优化,可以将时间复杂度降为 O(|E|log|V|),其中 |E| 表示边数。

import heapq

def dijkstra(adj, start):
    pq = []  # 优先队列
    heapq.heappush(pq, (0, start))
    dist = {v: float('inf') for v in adj}
    dist[start] = 0
    
    while pq:
        d, u = heapq.heappop(pq)
        if d != dist[u]:
            continue
        for v, weight in adj[u].items():
            if dist[u] + weight < dist[v]:
                dist[v] = dist[u] + weight
                heapq.heappush(pq, (dist[v], v))
    return dist
Bellman-Ford 算法

Bellman-Ford 算法也是解决单源最短路径问题的算法。和 Dijkstra 算法不同,在选择下一个顶点扩展时,Bellman-Ford 算法会扩展所有的边。因此,该算法可以处理负权边的情况。

Bellman-Ford 算法的时间复杂度为 O(|V||E|),其中 |V| 表示顶点数,|E| 表示边数。

def bellman_ford(adj, start):
    dist = {v: float('inf') for v in adj}
    dist[start] = 0

    for i in range(len(adj) - 1):
        for u in adj:
            for v, weight in adj[u].items():
                if dist[u] + weight < dist[v]:
                    dist[v] = dist[u] + weight

    for u in adj:
        for v, weight in adj[u].items():
            if dist[u] + weight < dist[v]:
                return None

    return dist
Floyd Warshall 算法

Floyd Warshall 算法是解决所有点对之间最短路径的经典算法。该算法使用动态规划的思想,它通过中间点的枚举来依次逼近最短路径。

Floyd Warshall 算法的时间复杂度为 O(|V|^3),其中 |V| 表示顶点数。

def floyd_warshall(adj):
    dist = {u: {v: float('inf') for v in adj} for u in adj}
    for u in adj:
        dist[u][u] = 0
    for u in adj:
        for v, weight in adj[u].items():
            dist[u][v] = weight

    for k in adj:
        for u in adj:
            for v in adj:
                dist[u][v] = min(dist[u][v], dist[u][k] + dist[k][v])

    return dist
总结

Dijkstra 算法、Bellman-Ford 算法以及 Floyd Warshall 算法都是解决最短路径问题的经典算法。在实际应用中,我们需要根据实际情况来选择合适的算法。如果图中不存在负权边,那么 Dijkstra 算法和贪心策略比较契合,效率相对较高。如果图中存在负权边,那么 Bellman-Ford 算法是较为合适的选择。最后,如果需要计算所有点对之间的最短路径,Floyd Warshall 算法可以获得较好的效果。