【每日一题Day47】LC1687从仓库到码头运输箱子 | 动态规划

从仓库到码头运输箱子【LC1687】

你有一辆货运卡车,你需要用这一辆车把一些箱子从仓库运送到码头。这辆卡车每次运输有 箱子数目的限制总重量的限制

给你一个箱子数组 boxes 和三个整数 portsCount, maxBoxesmaxWeight ,其中 boxes[i] = [portsi, weighti]

  • portsi 表示第 i 个箱子需要送达的码头, weightsi 是第 i 个箱子的重量。
  • portsCount 是码头的数目。
  • maxBoxesmaxWeight 分别是卡车每趟运输箱子数目和重量的限制。

箱子需要按照 数组顺序 运输,同时每次运输需要遵循以下步骤:

  • 卡车从 boxes 队列中按顺序取出若干个箱子,但不能违反 maxBoxesmaxWeight 限制。
  • 对于在卡车上的箱子,我们需要 按顺序 处理它们,卡车会通过 一趟行程 将最前面的箱子送到目的地码头并卸货。如果卡车已经在对应的码头,那么不需要 额外行程 ,箱子也会立马被卸货。
  • 卡车上所有箱子都被卸货后,卡车需要 一趟行程 回到仓库,从箱子队列里再取出一些箱子。

卡车在将所有箱子运输并卸货后,最后必须回到仓库。

请你返回将所有箱子送到相应码头的 最少行程 次数。

2022/12/05
啊啊啊 没时间做了 打了一天工 然后晚上给室友过生日啦 好高兴 以后再也没有这样好的室友啦 请一天假 sososorry
2022/12/06
我觉得把最普通的dp写出来就不错了 超时不是我的问题是数据的问题…

  • 思路:首先我们要尽可能在一趟行程中搬运更多的箱子,一趟行程可以搬运的最多箱子由箱子的个数、箱子的重量以及箱子的目的地决定

  • 动态规划【超时】
  • 思路:首先我们要尽可能在一次运送中搬运更多的箱子,一次运送可以搬运的最多箱子由箱子的个数、箱子的重量以及箱子的目的地决定,如果想要一次性运送第i个至第j个箱子,那么必须满足箱子总个数小于maxBoxes、总重量小于maxWeight,那么运送这些箱子所需要的行程数为相邻两个箱子目的地不相等的次数。每运送一次货物还需要一趟行程返回仓库,因此还需要一趟行程,最后返回总共需要的最少行程数即可

    • 使用前缀和的方式快速计算第i个至第j个箱子的重量weight以及相邻两个箱子目的地不相同的个数diff
    • 使用动态规划的方法计算运送所有箱子需要的最少行程数
  • 实现:为了方便描述 i i i的下标从1开始,指代boxes数组下标为 i − 1 i-1 i1的箱子 j j j的下标从0开始

    前缀和

    • weight[i]:表示前 i i i个箱子的重量总和
      • i i i个到第 j j j个箱子的重量为: w e i g h t [ j ] − w e i g h t [ i ] weight[j]-weight[i] weight[j]weight[i]
    • diff[i]:表示前 i i i个箱子中相邻两个箱子目的地不同的个数
      • i i i个到第 j j j个箱子中相邻两个箱子目的地不相等的次数为: d i f f [ j ] − d i f f [ i ] diff[j]-diff[i] diff[j]diff[i]

    动态规划

    1. 确定dp数组(dp table)以及下标的含义

      dp[i]:运送前i个箱子需要的最少行程数

    2. 确定递推公式

      对于第i个箱子,需要枚举上次一运送的最后一个箱子 j j j,那么这次需要运送的箱子为 [ j + 1 , i ] [j+1,i] [j+1,i],首先需要判断箱子重量和箱子个数是否满足要求,如果满足要求才可以一次性从仓库装入卡车,然后才可以通过diffdp数组得到运送至对应的码头所需要的行程数。

      因此dp公式为
      d p [ i ] = m i n ( d p [ i ] , d p [ j ] + d i f f [ i ] − d i f f [ j + 1 ] + 2 ) dp[i]=min(dp[i],dp[j]+diff[i]-diff[j+1]+2)\\ dp[i]=min(dp[i],dp[j]+diff[i]diff[j+1]+2)
      所需要满足的条件为
      0 ≤ j < i i − j ≤ m a x B o x e s w e i g h t s [ i ] − w e i g h t s [ j ] ≤ m a x W e i g h t s 0\le j \lt i \\ i-j\le maxBoxes\\ weights[i]-weights[j] \le maxWeights 0j<iijmaxBoxesweights[i]weights[j]maxWeights

    3. 如何初始化

      • d p [ 0 ] = 0 dp[0]=0 dp[0]=0;
      • 其他设置为最大值
    4. 确定遍历顺序

      由dp公式可知,外层正序遍历行i,内层正序遍历列j

    5. 举例推导dp数组

  • 代码

    class Solution {
        public int boxDelivering(int[][] boxes, int portsCount, int maxBoxes, int maxWeight){
            int n = boxes.length;
            int[] weights = new int[n + 1];
            int[] diff = new int[n + 1];
            int[] dp = new int [n + 1];
            for (int i = 0; i < n; i++){
                weights[i + 1] = weights[i] + boxes[i][1];
                if ( i > 0 && boxes[i - 1][0] != boxes[i][0]){
                    diff[i + 1] = diff[i] + 1;
                }else{
                    diff[i + 1] = diff[i];
                }
    
            }
            for (int i = 1; i <= n; i++){
                dp[i] = Integer.MAX_VALUE;
                for (int j = 0; j < i; j++){
                    if (i - j <= maxBoxes && weights[i] - weights[j] <= maxWeight){
                        dp[i] = Math.min(dp[i],dp[j] + diff[i] - diff[j + 1] + 2);
                    }
                }
            }
            return dp[n];
        }
    }
    
    • 复杂度

      • 时间复杂度: O ( n 2 ) O(n^2) O(n2) n n n为箱子个数
      • 空间复杂度: O ( n 2 ) O(n^2) O(n2)
动态规划+单调队列
  • 优化思路:不想优化了!!!!
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值