787. Cheapest Flights Within K Stops

Description

There are n cities connected by m flights. Each fight starts from city uand arrives at v with a price w.

Now given all the cities and fights, together with starting city src and the destination dst, your task is to find the cheapest price from src to dst with up to k stops. If there is no such route, output -1.

Example 1:
Input:
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 1
Output: 200
Explanation:
The graph looks like this:

787. Cheapest Flights Within K Stops_第1张图片
image

The cheapest price from city 0 to city 2 with at most 1 stop costs 200, as marked red in the picture.

Example 2:
Input:
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 0
Output: 500
Explanation:
The graph looks like this:

787. Cheapest Flights Within K Stops_第2张图片
image

The cheapest price from city 0 to city 2 with at most 0 stop costs 500, as marked blue in the picture.

Note:

  • The number of nodes n will be in range [1, 100], with nodes labeled from 0 to n`` - 1.
  • The size of flights will be in range [0, n * (n - 1) / 2].
  • The format of each flight will be (src, ``dst``, price).
  • The price of each flight will be in the range [1, 10000].
  • k is in the range of [0, n - 1].
  • There will not be any duplicated flights or self cycles.

Solution

Dijkstra

Dijkstra的变种。原本Dijkstra需要使用一个HashMap来保存已经找到最短路径的节点们,从而避免节点重复被处理(但路径更长)而导致性能变差甚至死循环。但这道题不需要,而且也不能这么做,如果加上Set used,会导致corner case出错。这是为什么呢?因为这道题求的并不严格是最短路径,而是满足某种条件的最短路径。所以考虑这种情况:
从a -> d有两条路径,要求stops < 2
a -> b -> c -> d,以及a -> b -> d。可能出现的一种情况是,path1实际上是最短的,此时b、c已经标记为visited,但是由于stops数量超过限制,d没有得到更新;而a -> b ->d这条路径,由于b已经visited过了,所以不会被放入队列!

所以必须不能用visited set。因为对节点数目有限制,所以只需要判断当前节点所在路径上的节点数是否还小于K即可,这样就不会陷入死循环。

另外需要注意的是,当在队列中第一次遇到某个节点node,此时node.price就是最短的了!因为后续即便再次遇到node,price只会更大。所以在队列中取出节点city为dst时,可以果断返回了。(此时如果不返回,可能会导致死循环)。

class Solution {
    public int findCheapestPrice(int n, int[][] flights, int src, int dst, int K) {
        Map> map = new HashMap<>();
        for (int i = 0; i < n; ++i) {
            map.put(i, new HashMap<>());
        }
        
        for (int[] flight : flights) {
            map.get(flight[0]).put(flight[1], flight[2]);
        }
        
        PriorityQueue queue 
            = new PriorityQueue<>((a, b) -> a.price - b.price);
        queue.offer(new Tuple(src, 0, -1));
        
        while (!queue.isEmpty()) {
            Tuple curr = queue.poll();
            
            if (curr.city == dst) {
                return curr.price;
            }
            
            if (curr.stops == K) {
                continue;
            }
            
            for (Map.Entry next : map.get(curr.city).entrySet()) {
                queue.offer(new Tuple(next.getKey()
                                   , curr.price + next.getValue(), curr.stops + 1));
            }
        }
        
        return -1;
    }
    
    class Tuple {
        int city;
        int price;
        int stops;
        
        public Tuple(int c, int p, int s) {
            city = c;
            price = p;
            stops = s;
        }
    }
}

你可能感兴趣的:(787. Cheapest Flights Within K Stops)