搜索与图论之最短路

这篇博客介绍了多种图论问题的解决方案,包括网络延迟时间的计算和最便宜航班路径的寻找。通过四种不同的方法(优先队列BFS、普通队列BFS、DFS和Floyd算法)解决网络延迟时间问题,同时展示了三种方法(普通队列BFS、优先队列BFS和DFS)解决最便宜航班问题。此外,还涉及了阈值距离内邻居最少的城市和无向图中最短路径的问题,分别使用Floyd算法和BFS/DFS求解。
摘要由CSDN通过智能技术生成

目录链接:搜索与图论


743. 网络延迟时间

图之网络延迟时间[Samoyed]
方法1:优先队列BFS
public int networkDelayTime(int[][] times, int N, int K) {
    //建图,key是当前节点的 value的0 只是其邻居节点,1 是距离 即u->v  花费w
    Map<Integer, Map<Integer, Integer>> graph = new HashMap<>();
    for (int[] t : times) {
        graph.putIfAbsent(t[0], new HashMap<>());
        graph.get(t[0]).put(t[1], t[2]);
    }
    //采用优先队列存储, 0指的是当前走的距离,1指的是走到当前的节点Node 按距离从小到大排序,这个很关键
    Queue<int[]> pq = new PriorityQueue<>((a, b) -> (a[0] - b[0]));
    pq.offer(new int[]{0, K});//起始从K 节点开始,走到K节点花了0的距离
    boolean[] visited = new boolean[N + 1]; //下标从1开始,多放一个
    int ans = 0;//结果集
    while (!pq.isEmpty()) {
        int[] curr = pq.poll();
        //0 是走到当前节点的距离 1 是
        int currNode = curr[1], currDist = curr[0];
        if (visited[currNode]) continue;//当前点如果访问过,不需要再访问其邻居节点
        visited[currNode] = true;
        ans = currDist;
        N--;//所有的节点被遍历完,可以提前结束
        if (N == 0) return ans;
        if (graph.containsKey(currNode)) {//访问邻居节点,并更新当前的dist距离
            for (int next : graph.get(currNode).keySet()) {
                pq.offer(new int[]{currDist + graph.get(currNode).get(next), next});
            }
        }
    }
    return N == 0 ? ans : -1;
}
方法2:普通队列BFS
        public int networkDelayTime(int[][] times, int N, int K) {
            int INF = Integer.MAX_VALUE / 2;
            //构建graph
            Map<Integer, Map<Integer, Integer>> graph = new HashMap<>();
            for (int[] t : times) {
                graph.putIfAbsent(t[0], new HashMap<>());
                graph.get(t[0]).put(t[1], t[2]);
            }
            int[] dist = new int[N + 1];
            Arrays.fill(dist, INF);//需要初始化成INF,防止溢出,取INF/2
            Queue<Integer> q = new LinkedList<>();
            q.offer(K);
            dist[K] = 0;
            while (!q.isEmpty()) {
                int u = q.poll();
                if (graph.containsKey(u)) {
                    for (Map.Entry<Integer, Integer> e : graph.get(u).entrySet()) {
                        int v = e.getKey(), w = e.getValue();
                        if (dist[u] + w < dist[v]) {//松弛
                            dist[v] = dist[u] + w;
                            q.offer(v);
                        }
                    }
                }
            }
            int ans = 0;
            //跳过0这个不存在的节点
            for (int i = 1; i <= N; i++) {
                ans = Math.max(ans, dist[i]);
            }
            return ans == INF ? -1 : ans;
        }
方法3:DFS
        Map<Integer, Map<Integer, Integer>> graph;
        int[] dist;

        public int networkDelayTime(int[][] times, int N, int K) {
            int INF = Integer.MAX_VALUE / 2;
            //构建graph
            graph = new HashMap<>();
            for (int[] t : times) {
                graph.putIfAbsent(t[0], new HashMap<>());
                graph.get(t[0]).put(t[1], t[2]);
            }
            dist = new int[N + 1];
            Arrays.fill(dist, INF);//需要初始化成INF,防止溢出,取INF/2
            dist[K] = 0;
            dfs(K);
            int ans = 0;
            //跳过0这个不存在的节点
            for (int i = 1; i <= N; i++) {
                ans = Math.max(ans, dist[i]);
            }
            return ans == INF ? -1 : ans;
        }

        private void dfs(int u) {
            if (graph.containsKey(u)) {
                for (Map.Entry<Integer, Integer> e : graph.get(u).entrySet()) {
                    int v = e.getKey(), w = e.getValue();
                    if (dist[u] + w < dist[v]) {
                        dist[v] = dist[u] + w;
                        dfs(v);
                    }
                }
            }
        }
方法4:Floyd
public int networkDelayTime(int[][] times, int N, int K) {
    int INF = Integer.MAX_VALUE / 2;
    int[][] dist = new int[N + 1][N + 1];
    for (int i = 0; i <= N; i++) Arrays.fill(dist[i], INF);
    for (int[] t : times) {
        int u = t[0], v = t[1], w = t[2];
        dist[u][v] = w;
    }
    dist[K][K] = 0;//很关键,一定要初始化
    for (int k = 1; k <= N; k++) {
        for (int u = 1; u <= N; u++) {
            for (int v = 1; v <= N; v++) {
                dist[u][v] = Math.min(dist[u][v], dist[u][k] + dist[k][v]);
            }
        }
    }
    int ans = -1;
    for (int i = 1; i <= N; i++) {
        ans = Math.max(ans, dist[K][i]);
    }
    return ans == INF ? -1 : ans;
}

787. K 站中转内最便宜的航班

方法1:普通队列BFS
        public int findCheapestPrice(int N, int[][] flights, int src, int dst, int K) {
            //构建图 u->v w
            Map<Integer, List<int[]>> graph = new HashMap<>();
            for (int[] f : flights) {
                graph.putIfAbsent(f[0], new ArrayList<>());
                graph.get(f[0]).add(new int[]{f[1], f[2]});
            }
            Queue<int[]> q = new LinkedList<>();
            q.offer(new int[]{src, 0});//0 表示当前点,1表示的是到达当前点的距离dist
            int ans = Integer.MAX_VALUE;
            int level = 0;
            while (!q.isEmpty()) {
                int size = q.size();
                for (int i = 0; i < size; i++) {
                    int[] curr = q.poll();
                    int u = curr[0], dist = curr[1];
                    if (u == dst) ans = Math.min(ans, dist);//找到目的地站
                    if (graph.containsKey(u)) {
                        for (int[] next : graph.get(u)) {
                            if (dist + next[1] > ans) continue;//松弛
                            q.offer(new int[]{next[0], dist + next[1]});
                        }
                    }
                }
                //先比较level 与K 再执行++ 的,bfs的层数,类似水波纹的一圈一圈的,一层表示经过一个站
                if (level++ > K) break;
            }
            return ans == Integer.MAX_VALUE ? -1 : ans;
        }
方法2:优先队列BFS(Dijkstra)
public int findCheapestPrice(int N, int[][] flights, int src, int dst, int K) {
    Map<Integer, Map<Integer, Integer>> graph = new HashMap<>();
    for (int[] f : flights) {
        graph.putIfAbsent(f[0], new HashMap<>());
        graph.get(f[0]).put(f[1], f[2]);
    }
    Queue<int[]> pq = new PriorityQueue<>((a, b) -> (a[0] - b[0]));
    pq.offer(new int[]{0, src, K + 1}); //存的依次是到达当前点v的距离,当前点v,已经经过的站数
    while (!pq.isEmpty()) {
        int[] curr = pq.poll();
        int dist = curr[0], u = curr[1], stops = curr[2];
        if (u == dst) return dist;
        if (stops > 0) {
            if (graph.containsKey(u)) {
                for (Map.Entry<Integer, Integer> e : graph.get(u).entrySet()) {
                    int v = e.getKey(), w = e.getValue();
                    pq.offer(new int[]{dist + w, v, stops - 1});
                }
            }
        }

    }
    return -1;
}
方法3:DFS
Map<Integer, List<int[]>> graph;
int ans = Integer.MAX_VALUE;

public int findCheapestPrice(int N, int[][] flights, int src, int dst, int K) {
    //构建图 u->v w
    graph = new HashMap<>();
    for (int[] f : flights) {
        graph.putIfAbsent(f[0], new ArrayList<>());
        graph.get(f[0]).add(new int[]{f[1], f[2]});
    }
    dfs(src, dst, K + 1, 0);
    return ans == Integer.MAX_VALUE ? -1 : ans;
}


private void dfs(int src, int dst, int K, int dist) {
    if (K < 0) return;
    if (src == dst) {
        ans = dist;
        return;
    }
    if (graph.containsKey(src)) {
        for (int[] f : graph.get(src)) {
            int u = f[0], w = f[1];
            if (dist + w > ans) continue;
            dfs(u, dst, K - 1, dist + w);
        }
    }
}
方法4:动态规划

//TODO

1334. 阈值距离内邻居最少的城市

方法1:Floyd
public int findTheCity(int N, int[][] edges, int distanceThreshold) {
    int INF = Integer.MAX_VALUE;
    int[][] graph = new int[N][N];
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            graph[i][j] = (i == j) ? 0 : INF;
        }
    }
    for (int[] e : edges) {
        int u = e[0], v = e[1], w = e[2];
        graph[u][v] = w;
        graph[v][u] = w;
    }

    for (int k = 0; k < N; k++) {
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if (i == j || graph[i][k] == INF || graph[k][j] == INF) continue;
                graph[i][j] = Math.min(graph[i][j], graph[i][k] + graph[k][j]);
            }
        }
    }
    PrintUtils.printMatrix(graph);
    int res = -1, min = N + 1;
    for (int i = 0; i < N; i++) {
        int cnt = 0;
        for (int j = 0; j < N; j++) {
            if (i != j && graph[i][j] <= distanceThreshold) {
                cnt++;
            }
        }
        if (min >= cnt) {
            min = cnt;
            res = i;
        }
    }
    return res;
}

814.无向图中的最短路径

方法1:BFS
class UndirectedGraphNode {
    int label;
    List<UndirectedGraphNode> neighbors;

    UndirectedGraphNode(int x) {
        label = x;
        neighbors = new ArrayList<UndirectedGraphNode>();
    }
}

public int shortestPath(List<UndirectedGraphNode> graph, UndirectedGraphNode A, UndirectedGraphNode B) {
    Queue<UndirectedGraphNode> q = new LinkedList<>();
    Set<UndirectedGraphNode> visited = new HashSet<>();
    q.offer(A);
    visited.add(A);
    int res = 0;
    while (!q.isEmpty()) {
        int size = q.size();
        res++;
        for (int i = 0; i < size; i++) {
            UndirectedGraphNode curr = q.poll();
            for (UndirectedGraphNode next : curr.neighbors) {
                System.out.printf("%d-->%d\n", curr.label, next.label);
                if (visited.contains(next)) continue;
                if (next.label == B.label) return res;
                q.offer(next);
                visited.add(next);
            }
        }
    }
    return -1;
}

1563.目的地的最短路径

方法1:BFS
int R, C;
int[][] dirs = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};

public int shortestPath(int[][] A) {
    // Write your code here
    R = A.length;
    C = A[0].length;
    Queue<int[]> q = new LinkedList<>();
    boolean[][] vis = new boolean[R][C];
    q.offer(new int[]{0, 0});
    vis[0][0] = true;
    int steps = 0;
    while (!q.isEmpty()) {
        int size = q.size();
        steps++;
        for (int i = 0; i < size; i++) {
            int[] c = q.poll();
            int cr = c[0], cc = c[1];
            for (int[] d : dirs) {
                int nr = cr + d[0], nc = cc + d[1];
                if (!inArea(nr, nc) || vis[nr][nc]) continue;
                if (A[nr][nc] == 2) return steps;
                if (A[nr][nc] == 1) continue;
                q.offer(new int[]{nr, nc});
                vis[nr][nc] = true;
            }
        }
    }
    return -1;
}

private boolean inArea(int r, int c) {
    return r >= 0 && r < R && c >= 0 && c < C;
}
方法2:DFS
  • 回溯标记状态,vis控制元素是否访问
int R, C;
int[][] dirs = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
boolean[][] vis;
int res;

public int shortestPath(int[][] A) {
    // Write your code here
    R = A.length;
    C = A[0].length;
    vis = new boolean[R][C];
    res = R * C;
    dfs(A, 0, 0, 0);
    return res == R * C ? -1 : res;
}


private void dfs(int[][] A, int r, int c, int steps) {
    for (int[] d : dirs) {
        int nr = r + d[0], nc = c + d[1];
        if (!inArea(nr, nc) || vis[nr][nc]) continue;
        if (A[nr][nc] == 2) {
            steps++;
            res = Math.min(res, steps);
            return;
        } else if (A[nr][nc] == 1) {
            continue;
        } else if (A[nr][nc] == 0) {
            steps++;
            vis[nr][nc] = true;
            dfs(A, nr, nc, steps);
            vis[nr][nc] = false;
            steps--;
        }


    }
}


private boolean inArea(int r, int c) {
    return r >= 0 && r < R && c >= 0 && c < C;
}

1723.网格中的最短路径//

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值