leetcode 787. Cheapest Flights Within K Stops(可以中转K次的航班)

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

Now given all the cities and flights, 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:
在这里插入图片描述
Example 2:
Input:
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 0
Output: 500

Constraints:

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.

给出一个有向图,求K次中转内起点到终点的最小cost。

思路:
(1) DFS
遍历每个起始点的下一终点,计算最小cost
可以用邻接链表,这里都放到HashMap里了
直接用DFS会超时,所以用dp数组记录已经计算过的结果

//17ms
class Solution {
    HashMap<Integer, HashMap<Integer, Integer>> map = new HashMap<>();
    Integer[][][] dp;
    public int findCheapestPrice(int n, int[][] flights, int src, int dst, int K) {
        if(flights == null || flights.length == 0) {
            return -1;
        }
        
        dp = new Integer[n][n][K+1];
        for(int i = 0; i < flights.length; i++) {
            if(map.containsKey(flights[i][0])) {
                map.get(flights[i][0]).put(flights[i][1], flights[i][2]);
            } else {
                HashMap<Integer, Integer> tmp = new HashMap<>();
                tmp.put(flights[i][1], flights[i][2]);
                map.put(flights[i][0], tmp);
            }
        }
        
        return dfs(src, dst, K);
    }
    
    int dfs(int src, int dst, int K) {
        int result = Integer.MAX_VALUE;
        if(src == dst) {
            return 0;
        }
        if(dp[src][dst][K] != null) {
            return dp[src][dst][K];
        }
        if(map.containsKey(src)) {
            HashMap<Integer, Integer> prices = map.get(src);
            if(K == 0) {
                if(prices.containsKey(dst)) {
                    return prices.get(dst);
                } else {
                    return -1;
                }
            }
            
            for(Integer key : map.get(src).keySet()) {
                int tmp = dfs(key, dst, K-1);
                
                if(tmp >= 0) {
                    result = Math.min(result, map.get(src).get(key) + tmp);
                }               
            }
            
        } else {
            return -1;
        }
        
        result = (result == Integer.MAX_VALUE? -1 : result);
        dp[src][dst][K] = result;
        return result;
    } 
}

(2) DP
用dp[k][dst]表示经过k步到dst,如果看成k次中转的话,就是k+1步到dst
src == dst时,是不需要坐飞机的,所以dp[i][src] = 0
而dp[i][v] = min(dp[i][v], dp[i-1][u] + cost[u][v])
也就是说,经过i 步到v的cost,等于经过i - 1 步到达u站,再经过1步从u站到v站,在所有cost中选择最小的

因为最后结果是k次中转,所以取k+1步,dp[k+1][dst]

初始化inf = 1e9,这样当dp[k+1][dst] > inf 时返回-1

//4ms
    public int findCheapestPrice(int n, int[][] flights, int src, int dst, int K) {
        if(flights == null || flights.length == 0) {
            return -1;
        }
        
        int inf = 100000000;
        
        int[][] dp = new int[K+2][n];
        for(int i = 0; i <= K+1; i++) {
            Arrays.fill(dp[i], inf);
            dp[i][src] = 0;
        }
        
        for(int i = 1; i <= K+1; i++) {
            for(int[] list : flights){
                dp[i][list[1]] = Math.min(dp[i][list[1]], 
                                          dp[i-1][list[0]] + list[2]);
            }
        }
        
        return dp[K+1][dst] >= inf ? -1 : dp[K+1][dst];
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值