题目描述
【统一限载货物数最小值】
火车站附近的货物中转站负责将到站货物运往仓库,小明在中转站负责调度2K辆中转车(K辆干货中转车,K辆湿货中转车)。
货物由不同供货商从各地发来,各地的货物是依次进站,然后小明按照卸货顺序依次装货到中转车上,一个供货商的货只能装到一辆车上,
不能拆装,但是一辆车可以装多家供货商的货;
中转车的限载货物量由小明统一制定,在完成货物中转的前提下,请问中转车的统一限载货物数最小值为多少。
输入描述
第一行length表示供货商数量 1 <= length <= 10^4
第二行goods表示供货数数组 1 <= goods[i] <= 10^4
第三行types表示对应货物类型,types[i]等于0或者1,0代表干货,1代表湿货
第四行k表示单类中转车数量1 <= k <= goods.length
输出描述
一个整数,表示中转车统一限载货物数
补充说明
中转车最多跑一趟仓库
干湿货物不能混装
解题思路
首先按照干货和湿货分别计算总货物数量,同时记录下其中最大的单个货物数量。然后根据单类中转车的数量,计算出干货和湿货的最小限载量,最终取其最大值作为最终的限载量的上限。
接下来,利用二分查找法找到符合条件的最小限载量。在二分查找过程中,每次计算出干货和湿货需要的中转车数量,判断总车数是否小于等于2k,并且最大货物数量是否小于等于限制值,根据这些条件移动左右指针,最终得到最小限载量。
时间复杂度:O(NlogM),其中 N 为货物数量,M 为货物总重量的上限,因为使用了二分查找,最多进行 logM 次操作。
空间复杂度:O(N),需要存储货物重量和湿/干属性。
参考代码
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读入数据长度
int length = scanner.nextInt();
// 初始化货物数组和类型数组
int[] goods = new int[length];
int[] types = new int[length];
// 读入货物数组和类型数组
for (int i = 0; i < length; i++) {
goods[i] = scanner.nextInt();
}
for (int i = 0; i < length; i++) {
types[i] = scanner.nextInt();
}
// 读入中转车数量上限
int k = scanner.nextInt();
// 统计干货和湿货的总数和最大货物重量
int totalDryGoods = 0;
int totalWetGoods = 0;
int maxGoods = 0;
for (int i = 0; i < length; i++) {
if (types[i] == 0) {
totalDryGoods += goods[i];
maxGoods = Math.max(maxGoods, goods[i]);
} else {
totalWetGoods += goods[i];
maxGoods = Math.max(maxGoods, goods[i]);
}
}
// 计算干货和湿货的中转车上限
int maxDryGoods = totalDryGoods / k;
if (totalDryGoods % k != 0) {
maxDryGoods++;
}
int maxWetGoods = totalWetGoods / k;
if (totalWetGoods % k != 0) {
maxWetGoods++;
}
// 求干货和湿货的中转车上限的最大值
int maxLimit = Math.max(maxDryGoods, maxWetGoods);
// 二分查找,找到符合要求的最小中转车载重
int left = maxLimit;
int right = totalDryGoods + totalWetGoods;
while (left < right) {
int mid = (left + right) / 2;
// 计算干货和湿货需要的中转车数量
int numDryCars = getNumCars(totalDryGoods, mid);
int numWetCars = getNumCars(totalWetGoods, mid);
// 如果总中转车数量不超过上限,且最大货物重量不超过中转车载重,说明满足条件
if (numDryCars + numWetCars <= 2 * k && maxGoods <= mid) {
right = mid;
} else {
left = mid + 1;
}
}
// 输出符合条件的最小中转车载重
System.out.println(left);
}
// 计算所需的中转车数量
private static int getNumCars(int totalGoods, int limit) {
int numCars = totalGoods / limit;
if (totalGoods % limit != 0) {
numCars++;
}
return numCars;
}
}