1011. 在 D 天内送达包裹的能力

285 阅读3分钟

[1011. 在 D 天内送达包裹的能力]

「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。

题目描述

传送带上的包裹必须在 D 天内从一个港口运送到另一个港口。

传送带上的第 i 个包裹的重量为 weights[i]。每一天,我们都会按给出重量的顺序往传送带上装载包裹。我们装载的重量不会超过船的最大运载重量。

返回能在 D 天内将传送带上的所有包裹送达的船的最低运载能力。

示例

输入:weights = [1,2,3,4,5,6,7,8,9,10], days = 5

输出:15

解释:

船舶最低载重 15 就能够在 5 天内送达所有包裹,如下所示:

第 1 天:1, 2, 3, 4, 5

第 2 天:6, 7

第 3 天:8

第 4 天:9

第 5 天:10

思路

按照题目要求,需要的结果是能在 D 天内将传送带上的所有包裹送达的船的最低运载能力。求的是运载能力,即最在要求的时间内,船的运载量最小。这里涉及到两个变量,运载天数和船的运载量,题目已经给出了运载天数,那么可以从船的运载量开始思考。

那么,可以先想出在忽略天数的情况下考虑运载能力的范围。那么首先最小运载能力应该大于物品的最大值,才有可能完成任务,此时的天数为最大值,即货物的数量(一天运一件),最大运载能力应为物品重量的总和,这样就可以一天运走,再大没有必要,此时的天数的最小值为1天。可以发现运载量都可以对应到一个天数。

之后可以使用二分查找,计算当前运载量运输所需要的最小天数,不断的逼近D。得解。

代码实现

具体到代码实现,按照上述思路,使用二分查找时,我们需要左右界和判断条件。判断条件我们可以使用一个判断函数来实现,具体到这道题,就是判断,给定的货物,天数,运载量,能不能运走。这道题,左右界应为运载量的范围,左界为货物最大值,右界为货物之和。在进行二分查找时,会有多个运载量符合D天的要求,在这些值里面,只有最小的才符合要求。具体实现和注释见下面代码。

 class Solution {
 private:
     bool cantCarry(vector<int>weights,int D,int load){
         int curDay=1,curload=0;       // 判断在运载能力确定时,能不能在D内运完。
         for(int w:weights){
             if(curload+w>load){         // 加上这件物品超载,说明当天运量到上限,需要当天发
                 curload=0;  // 清空
                 ++curDay;   //天数加1
             }
             curload+=w;   // 装货
         } 
         return curDay>D;   // 求出运送的实际天数,判断给定的天数是不是运不完。
     }
 public:
     int shipWithinDays(vector<int>& weights, int D) {
         int  left= INT_MIN,right=0;
         for(int w:weights){
             left=max(left,w);
             right+=w;        //找出左右界
         }
         while(left<right){                // 二分查找,此处找的是符合条件的最小值
             int middle=left+(right-left)/2;
             if(cantCarry(weights,D,middle)){       //运不走,移动左,使变大,增加运载量 
                 left=middle+1;
             }
             else{                          // 运得走,移动右,使变小,逼近最小值 
                 right=middle;
             }
         }
         return left;  //循环结束时,执行的是left=middle+1,处于有效区间内。 
     }
 };