09.02_最短路径

最短路径

问题描述

最短路径算法用于求解图中两点间的最短距离,包括Dijkstra、Bellman-Ford、Floyd等算法。

Dijkstra算法

算法思想

  1. 基于贪心策略
  2. 适用于非负权图
  3. 可以使用优先队列优化
  4. 时间复杂度

代码实现

class Solution {
public:
    vector<int> dijkstra(vector<vector<pair<int, int>>>& adj, int start) {
        int n = adj.size();
        vector<int> dist(n, INT_MAX);
        dist[start] = 0;
        
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;
        pq.push({0, start});
        
        while (!pq.empty()) {
            auto [d, v] = pq.top();
            pq.pop();
            
            if (d > dist[v]) continue;
            
            for (auto [u, w] : adj[v]) {
                if (dist[v] + w < dist[u]) {
                    dist[u] = dist[v] + w;
                    pq.push({dist[u], u});
                }
            }
        }
        
        return dist;
    }
};
class Solution {
    public int[] dijkstra(List<List<int[]>> adj, int start) {
        int n = adj.size();
        int[] dist = new int[n];
        Arrays.fill(dist, Integer.MAX_VALUE);
        dist[start] = 0;
        
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
        pq.offer(new int[]{0, start});
        
        while (!pq.isEmpty()) {
            int[] cur = pq.poll();
            int d = cur[0], v = cur[1];
            
            if (d > dist[v]) continue;
            
            for (int[] edge : adj.get(v)) {
                int u = edge[0], w = edge[1];
                if (dist[v] + w < dist[u]) {
                    dist[u] = dist[v] + w;
                    pq.offer(new int[]{dist[u], u});
                }
            }
        }
        
        return dist;
    }
}
class Solution:
    def dijkstra(self, adj: List[List[Tuple[int, int]]], start: int) -> List[int]:
        n = len(adj)
        dist = [float('inf')] * n
        dist[start] = 0
        
        pq = [(0, start)]
        
        while pq:
            d, v = heapq.heappop(pq)
            
            if d > dist[v]:
                continue
            
            for u, w in adj[v]:
                if dist[v] + w < dist[u]:
                    dist[u] = dist[v] + w
                    heapq.heappush(pq, (dist[u], u))
        
        return dist

Floyd算法

算法思想

  1. 基于动态规划
  2. 适用于多源最短路
  3. 可以处理负权边
  4. 时间复杂度

代码实现

class Solution {
public:
    vector<vector<int>> floyd(vector<vector<int>>& graph) {
        int n = graph.size();
        vector<vector<int>> dist = graph;
        
        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]);
                    }
                }
            }
        }
        
        return dist;
    }
};
class Solution {
    public int[][] floyd(int[][] graph) {
        int n = graph.length;
        int[][] dist = new int[n][n];
        
        // 复制图
        for (int i = 0; i < n; i++) {
            dist[i] = Arrays.copyOf(graph[i], n);
        }
        
        // Floyd算法
        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] != Integer.MAX_VALUE && 
                        dist[k][j] != Integer.MAX_VALUE) {
                        dist[i][j] = Math.min(dist[i][j], 
                                            dist[i][k] + dist[k][j]);
                    }
                }
            }
        }
        
        return dist;
    }
}
class Solution:
    def floyd(self, graph: List[List[int]]) -> List[List[int]]:
        n = len(graph)
        dist = [[x for x in row] for row in graph]  # 深拷贝
        
        # Floyd算法
        for k in range(n):
            for i in range(n):
                for j in range(n):
                    if dist[i][k] != float('inf') and dist[k][j] != float('inf'):
                        dist[i][j] = min(dist[i][j], 
                                       dist[i][k] + dist[k][j])
        
        return dist

时间复杂度分析

算法 时间复杂度 空间复杂度
Dijkstra
Bellman-Ford
Floyd
SPFA

应用场景

  1. 导航系统
  2. 网络路由
  3. 社交网络
  4. 资源调度
  5. 游戏寻路

注意事项

  1. 权值的正负
  2. 边界情况
  3. 溢出处理
  4. 算法选择
  5. 优化方式

常见变形

  1. 带路径记录的Dijkstra
class Solution {
public:
    pair<vector<int>, vector<int>> dijkstraWithPath(vector<vector<pair<int, int>>>& adj, int start) {
        int n = adj.size();
        vector<int> dist(n, INT_MAX);
        vector<int> parent(n, -1);
        dist[start] = 0;
        
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;
        pq.push({0, start});
        
        while (!pq.empty()) {
            auto [d, v] = pq.top();
            pq.pop();
            
            if (d > dist[v]) continue;
            
            for (auto [u, w] : adj[v]) {
                if (dist[v] + w < dist[u]) {
                    dist[u] = dist[v] + w;
                    parent[u] = v;
                    pq.push({dist[u], u});
                }
            }
        }
        
        return {dist, parent};
    }
};
class Solution {
    public int[][] dijkstraWithPath(List<List<int[]>> adj, int start) {
        int n = adj.size();
        int[] dist = new int[n];
        int[] parent = new int[n];
        Arrays.fill(dist, Integer.MAX_VALUE);
        Arrays.fill(parent, -1);
        dist[start] = 0;
        
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
        pq.offer(new int[]{0, start});
        
        while (!pq.isEmpty()) {
            int[] cur = pq.poll();
            int d = cur[0], v = cur[1];
            
            if (d > dist[v]) continue;
            
            for (int[] edge : adj.get(v)) {
                int u = edge[0], w = edge[1];
                if (dist[v] + w < dist[u]) {
                    dist[u] = dist[v] + w;
                    parent[u] = v;
                    pq.offer(new int[]{dist[u], u});
                }
            }
        }
        
        return new int[][]{dist, parent};
    }
}
class Solution:
    def dijkstraWithPath(self, adj: List[List[Tuple[int, int]]], start: int) -> Tuple[List[int], List[int]]:
        n = len(adj)
        dist = [float('inf')] * n
        parent = [-1] * n
        dist[start] = 0
        
        pq = [(0, start)]
        
        while pq:
            d, v = heapq.heappop(pq)
            
            if d > dist[v]:
                continue
            
            for u, w in adj[v]:
                if dist[v] + w < dist[u]:
                    dist[u] = dist[v] + w
                    parent[u] = v
                    heapq.heappush(pq, (dist[u], u))
        
        return dist, parent
  1. 判断负环
class Solution {
public:
    bool hasNegativeCycle(vector<vector<pair<int, int>>>& adj) {
        int n = adj.size();
        vector<int> dist(n);
        
        // 进行n-1次松弛
        for (int i = 0; i < n - 1; i++) {
            for (int v = 0; v < n; v++) {
                for (auto [u, w] : adj[v]) {
                    if (dist[v] + w < dist[u]) {
                        dist[u] = dist[v] + w;
                    }
                }
            }
        }
        
        // 检查是否还能继续松弛
        for (int v = 0; v < n; v++) {
            for (auto [u, w] : adj[v]) {
                if (dist[v] + w < dist[u]) {
                    return true;  // 存在负环
                }
            }
        }
        
        return false;
    }
};
class Solution {
    public boolean hasNegativeCycle(List<List<int[]>> adj) {
        int n = adj.size();
        int[] dist = new int[n];
        
        // 进行n-1次松弛
        for (int i = 0; i < n - 1; i++) {
            for (int v = 0; v < n; v++) {
                for (int[] edge : adj.get(v)) {
                    int u = edge[0], w = edge[1];
                    if (dist[v] + w < dist[u]) {
                        dist[u] = dist[v] + w;
                    }
                }
            }
        }
        
        // 检查是否还能继续松弛
        for (int v = 0; v < n; v++) {
            for (int[] edge : adj.get(v)) {
                int u = edge[0], w = edge[1];
                if (dist[v] + w < dist[u]) {
                    return true;  // 存在负环
                }
            }
        }
        
        return false;
    }
}
class Solution:
    def hasNegativeCycle(self, adj: List[List[Tuple[int, int]]]) -> bool:
        n = len(adj)
        dist = [0] * n
        
        # 进行n-1次松弛
        for i in range(n - 1):
            for v in range(n):
                for u, w in adj[v]:
                    if dist[v] + w < dist[u]:
                        dist[u] = dist[v] + w
        
        # 检查是否还能继续松弛
        for v in range(n):
            for u, w in adj[v]:
                if dist[v] + w < dist[u]:
                    return True  # 存在负环
        
        return False

经典例题

  1. 【模板】单源最短路Ⅰ ‖ 无权图
  2. 【模板】单源最短路Ⅲ ‖ 非负权图
  3. 迷宫问题
  4. 小红送外卖
  5. 游游出游
  6. 小红修道路
牛客代码笔记-牛栋 文章被收录于专栏

汗牛充栋,学海无涯。<br/> 内含算法知识点讲解,以及牛客题库精选例题。<br/> 学习算法,从牛栋开始。

全部评论

相关推荐

点赞 评论 收藏
分享
评论
2
1
分享

创作者周榜

更多
牛客网
牛客企业服务