lintcode 1029 · 寻找最便宜的航行旅途(最多经过k个中转站)【有向图,BFS VIP】

题目链接,描述

https://www.lintcode.com/problem/1029

有n个城市被一些航班所连接。每个航班 (u,v,w) 从城市u出发,到达城市v,价格为w。

给定城市数目 n,所有的航班flights。你的任务是找到从起点src到终点站dst的最便宜线路的价格,而旅途中最多只能中转K次。

如果没有找到合适的线路,返回 -1。


总城市数 n 在 1-100 之间,每个城市被标号为 0 到 n-1。
航线的总数在 0 到 n * (n - 1) / 2 之间
每条航线会被以 [出发站,终点站,价格] 的形式展现。
每条航线的价格都在 1-10000之间。
中转站的总数限制范围为 0 到 n-1 之间。
不会有重复或者自环航线出现
样例
样例 1:

输入: 
  n = 3,
  flights = [[0,1,100],[1,2,100],[0,2,500]],
  src = 0, dst = 2, K = 0
输出: 500
样例 2:

输入: 
  n = 3,
  flights = [[0,1,100],[1,2,100],[0,2,500]],
  src = 0, dst = 2, K = 1
输出: 200

解题知识点

法2:SPFA。在Bellman-Ford算法基础上进行优化,用一个队列,
每次只有当松弛操作会产生更优路线的时候才会将被松弛的边的那个到达点加入队列中,
进行下面的优化。同时,开一个数组记录源点到其余顶点的最短路的长度,
在每次松弛的时候,都更新之;而一旦发现某个点更新完后其最短路长度已经达到了K + 1 了,
也不能将其加入队列,因为用其更新别的点的最短路只会产生路径长度更长的最短路,这是不符合要求的

答案

public class Solution {
    /**
     * @param n: a integer
     * @param flights: a 2D array
     * @param src: a integer
     * @param dst: a integer
     * @param k: a integer
     * @return: return a integer
     */
    public int findCheapestPrice(int n, int[][] flights, int src, int dst, int k) {
           /*
        法2:SPFA。在Bellman-Ford算法基础上进行优化,用一个队列,
        每次只有当松弛操作会产生更优路线的时候才会将被松弛的边的那个到达点加入队列中,
        进行下面的优化。同时,开一个数组记录源点到其余顶点的最短路的长度,
        在每次松弛的时候,都更新之;而一旦发现某个点更新完后其最短路长度已经达到了K + 1 了,
        也不能将其加入队列,因为用其更新别的点的最短路只会产生路径长度更长的最短路,这是不符合要求的
         */
        if(flights ==null || flights.length ==0 || flights[0].length ==0)
            return 0;
        Map<Integer, List<int[]>> graph = buildGraph(flights);
        int[] dis = new int[n];
        Arrays.fill(dis,Integer.MAX_VALUE);
        dis[src] = 0;
        //记录当前算出的到该顶点的最短的边的数量
        int[] count = new int[n];
        //记录当前顶点是否已经存在于队列中
        boolean[] visited = new boolean[n];
        Queue<Integer> queue = new LinkedList<>();
        queue.add(src);
        while (!queue.isEmpty()){
            int cur = queue.poll();
            visited[cur] = false;

            if(!graph.containsKey(cur)) continue;

            for(int[] next: graph.get(cur)){
                int nextpoint = next[0],disFromCur = next[1];

                if(dis[nextpoint] > dis[cur] + disFromCur) {
                    dis[nextpoint] = dis[cur]+disFromCur;
                    count[nextpoint] = count[cur]+1;

                    //判断一下nextpoint的最短路径的边的数量是小于等于k的
                    //如果不满足也不能加入队列
                    if(!visited[nextpoint] && count[nextpoint] <=k){
                        queue.add(nextpoint);
                        visited[nextpoint] = true;
                    }
                }
            }
        }


        return dis[dst] ==Integer.MAX_VALUE?-1:dis[dst];
    }

    public static Map<Integer,List<int[]>> buildGraph(int[][] arr){
        Map<Integer,List<int[]>> graph = new HashMap<>();
        for (int[] v : arr) {
            int a = v[0],b=v[1],c=v[2];
            if(!graph.containsKey(a))
                graph.put(a,new ArrayList<>());
            graph.get(a).add(new int[]{b,c});
        }
        return graph;
    }
}

你可能感兴趣的:(宽度优先,算法)