43、K 站中转内最便宜的航班(即求最短路径)

 一、问题

有 n 个城市通过一些航班连接。给你一个数组 flights ,其中 flights[i] = [fromi, toi, pricei] ,表示该航班都从城市 fromi 开始,以价格 pricei 抵达 toi 。

现在给定所有的城市和航班,以及出发城市 src 和目的地 dst,你的任务是找到出一条最多经过 k 站中转的路线,使得从 src 到 dst 的 价格最便宜 ,并返回该价格。 如果不存在这样的路线,则输出 -1。

 

 二、思路

方法一:迪杰斯特拉算法

与 Dijkstra 算法的不同:限制了可以中转 K 次。我们来看下面的例子。

image.png

 

用一个和dist等长的数组stops去记录这个最优价格dist[i]所对应的剩余中转站个数。如果weight_i + dist >= dist[i],我们要看一下当前剩余的中转站次数是否大于stops[i],如果是的话我们依然要将节点i入栈。这样如果最优距离对应的路是一条死胡同,我们也可以检验现在的路。

class Solution {
    public int findCheapestPrice(int n, int[][] flights, int src, int dst, int k) {
        // Build the graph
        int mat[][] = new int[n][n];
        for (int flight[] : flights) {
            mat[flight[0]][flight[1]] = flight[2];
        }

        // min heap: {(vertex, cost, stops), ...}
        PriorityQueue<int[]> minHeap = new PriorityQueue<>((e1, e2) -> e1[1] - e2[1]);

        // costs[i]: min cost from src to vertex i
        // stops[i]: number of stops of the corresponding cheapest cost for vertex i
        int costs[] = new int[n];
        int stops[] = new int[n];
        Arrays.fill(costs, Integer.MAX_VALUE);

        // Dijkstra Algorithm within k
        minHeap.offer(new int[] {src, 0, k});
        while (!minHeap.isEmpty()) {
            int elem[] = minHeap.poll();
            int vertex = elem[0], cost = elem[1], stop = elem[2];

            if (vertex == dst) {
                return cost;
            } else if (stop < 0) {
                continue;
            }

            for (int i = 0; i < n; ++i) {
                if (mat[vertex][i] > 0) {
                    int costI = costs[i], costVI = mat[vertex][i];
                    if (cost + costVI < costI) {
                        minHeap.offer(new int[] {i, costVI + cost, stop - 1});
                        costs[i] = costVI + cost;
                        stops[i] = stop - 1;
                    } else if (stops[i] < stop - 1) {
                        minHeap.offer(new int[] {i, costVI + cost, stop - 1});
                    }
                }
            }
        }
        return -1;
    }
}

 

最短路径,是指两顶点之间经过的边上权值之和最少的路径。并且我们称路径上的第一个顶点是源点,最后一个顶点是终点。

关于最短路径主要有两种算法:迪杰斯特拉(Dijkstra) 算法弗洛伊德(Floyd) 算法

 

三、迪杰斯特拉算法

计算的是 从某个源点到其余各顶点的最短路径。具体步骤如下:

  1. 先将源点v0加入顶点集S,计算v0到其他顶点的距离(此时S中只有v0,故不存在中转顶点);
  2. v0到达顶点vk的距离最小,则将vk加入到集合S中,此时多了一个中转顶点vk
  3. 所以要对剩余的各个顶点的最短路径长度进行更新
  4. 原来v0到vi的最短路径长度为D[i],加入k作为中间顶点的中转路径长度为:D[k]+Garcs[k][i],若D[k]+Garcs[k][i]<D[i],则用D[k]+Garcs[k][i]取代D[i]。
  5. 更新后,再选择数组D中值最小的顶点加入到顶点集S中,如此进行下去,直至图中所有顶点加入到顶点集S为止。

 

 

 

 四、弗洛伊德算法

计算的是 每个顶点之间的最短路径。 

 

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值