K 站中转内最便宜的航班--动态规划

在这里插入图片描述
在这里插入图片描述

思路:我们可以先从第一站开始找,比如在0–>1–>3|0–>2–>3中,我把第一站定义为0–>1|0–>2。先找第一个也就是在k=1时
也就是0–>1|0–>2时,它们各自的价格。然后开始找k-n(0<n<k)个站的价格、一直找到第k个站的价格。
比如k=2,就要找1–>3|2–>3,这个时候因为有前面0–>1|0–>2的基础,我们可以合起来就有0–>1–>3|0–>2–>3的价格
了,这个时候我们发现1–>3跟2–>3终点重合起来了,这个时候我们就要判断他们两个方案的最小价格了。所以按照这个推理
我们也可以推理k=3,k=4…一直到k=k。 总结一下我们这个思路,就是把k化成每一个小问题,比如上面那个例子,K=2,我们先找K=1时各站的价格,然后在k=1的基础上
找k=2的价格、k=3的价格…,最后得出在K-1的基础上,找到K的最优解。

          算法设计:按照思路,我们要一个数组存每一个终点站的价格。
                   如果是一维数组:
                                状态:dp[i] = 价格;i代表每一个终点站
                                状态转移方程:dp[flights[j][1]] = Math.max(dp[flights[j][1]],dp[flights[j][0]]+flights[2]);
                   这个时候,我们发现,随着j的增大,我们在寻找出k=1后,会马上寻找k=2,接着又是寻找k=1,然后是k=2。比如:
                   在上面思路中我们说到,先找0-->1|0-->2,然后再找1-->3|2-->3。第一站肯定是从起始点出发,然后再计划下一站。
                   我们现在这个设计不能做到上面的效果
          //说明一下:这个可以计算起点到目的地的最优解,但不能确定中转站数。
                   解决方案:两个数组。

                             状态:dp_1[i] = 价格;dp_2[i] = 价格;i代表每一个终点站
                             状态转移方程:dp_1[flights[j][1]] = Math.max(dp_1[flights[j][1]],dp_2[flights[j][0]]+flights[2]);
                             初始化:dp_1[起点] = 0;dp_2[起点] = 0;
                                    dp_1[其他] = Integer.MAX_VALUE/2;dp_2[其他] = Integer.MAX_VALUE/2;

                            在0-->1-->3中,当k = 1时,我们让1-->3不能录入数据。
                            在0-->2-->3中,当k = 1时,我们让2-->3不能录入数据。
                            只有在k=2时,我们才让1-->3|2-->3录入
                   所以,我们根据题目的提示,得到:最大的价格不会超过100*10000元。我们给两个dp初始化比100*10000大的数。
                                                然后起点站初始化0;两个数组交替使用,k=1时用dp_1,k=2时用dp_2;k=3时用dp_1...
                        flights = {[0,1,20],[1,3,10],[0,2,10],[2,3,5]} --->[起点,终点,价格]
                   分析:k = 1时,我们dp_1[0] = 0,dp_1[1] = Math.min(dp_1[1],dp_2[0]+flights[0]])
                        dp_1[3] = Math.min(dp_1[2],dp_2[1]+flights[1]])--->这步很重要,dp_1[2]此时 = Integer.MAX_VALUE/2;
                        dp_2[1]此时 = Integer.MAX_VALUE/2;再加上flights[1]就会比dp_1[3]大了,所以dp_1[3]还是等于Integer.MAX_VALUE/2;
                    结论:我们因此可以得出,这个方案符合我们的思路
public static int findCheapestPrice(int n, int[][] flights, int src, int dst, int K) {
        int dp_1[] = new int[n];
        int dp_2[] = new int[n];
        int MAX = Integer.MAX_VALUE/2;
        //初始化(因为100*10000=100000<MAX)
        for (int i = 0;i < n;i++){
                dp_1[i] = MAX;
                dp_2[i] = MAX;
        }
        dp_1[src] = 0;
        dp_2[src] = 0;
        //K是中转站数
        for(int i = 0;i <= K;i++){
            for(int item[]: flights){
                //这里我们存dp_1时,要用到dp_2来做判断
                if((~i & 1) == 0)
                    dp_1[item[1]] = Math.min(dp_1[item[1]],dp_2[item[0]]+item[2]);
                else
                    dp_2[item[1]] = Math.min(dp_2[item[1]],dp_1[item[0]]+item[2]);
            }
        }
        int money = dp_1[dst]>dp_2[dst]?dp_2[dst]:dp_1[dst];
        //如果不存在就返回-1
        if(money == MAX) money=-1;
        return money;
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值