全网最全面的华为OD机试真题汇总,100%原题题库,不需要开会员即可查看全部内容,更多考题请查看真题库。
真题库:https://www.yuque.com/codernav.com/od
题目:统一限载货物数最小值
知识点二分查找
时间限制:1s 空间限制:64MB 限定语言:不限
题目描述:
火车站附近的货物中转站负责将到站货物运往仓库,小明在中转站负责调度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
输出描述:
一个整数,表示中转车统一限载货物数
补充说明:
1.中转车最多跑一趟仓库
示例1
输入:
4
3 2 6 3
0 1 1 0
2
输出:
6
说明:
货物1和货物4为干货,由2两干货中转车中转,每辆车运输一个货物,限载为3
货物2和货物3为湿货,由2两湿货中转车中转,每辆车运输一个货物,限载为6
这样中转车统一限载货物数可以设置为6(干货车和湿货车限载最大值),是最小的取值
示例2
输入:
4
3 2 6 8
0 1 1 1
1
输出:
16
说明:
货物1为干货,由1两干货中转车中转,限载为3
货物2、货物3和货物4为湿货,由1两湿货中转车中转,限载为16
这样中转车统一限载货物数可以设置为16(干货车和湿货车限载最大值),是最小的取值
解题思路:
4
3 2 3 5
1 1 1 1
2
首先统计出湿货物的总重量countWet=3+2+3+5=13,湿货物列表listWet={3,2,3,5};k为2,我们新建长度为2的数组vans=【0,0】作为货车载重数组;对货物列表进行排序{2,3,3,5},方便后面的遍历。
求运送湿货物的最小货车载量:
1、题目中的k为2,也就是是说2辆车需要运送重量13的货物,由此我们可以求得13/2=6+1=7,每辆车的最小载量应该为7;湿货物中最大的货物重量为5;5<7,这样一来,我们的最小载量应该为7;而最大载量肯定就是货物的总量13
2、这里我们使用二分法:
1)7+13 / 2 = 10,假定载量为10;遍历货物列表:
Weight=2,遍历货车数组【0,0】;因为vans[0]+2<10,放在第一辆车【2,0】;
Weight=3,遍历货车数组【2,0】;因为vans[0]+3<10,放在第一辆车【5,0】;
Weight=3,遍历货车数组【5,0】;因为vans[0]+3<10,放在第一辆车【8,0】;
Weight=5,遍历货车数组【8,0】;因为vans[0]+5>10,vans[1]+5<10,放在第二辆车【8,5】
2)说明载重10是可以运输的,此时最小载重为7,最大载重10;那我们继续进行二分;7+10/2 = 8,假定载重为8;遍历货物列表:
Weight=2,遍历货车数组【0,0】;因为vans[0]+2<8,放在第一辆车【2,0】;
Weight=3,遍历货车数组【2,0】;因为vans[0]+3<8,放在第一辆车【5,0】;
Weight=3,遍历货车数组【5,0】;因为vans[0]+3<=8,放在第一辆车【8,0】;
Weight=5,遍历货车数组【8,0】;因为vans[0]+5>10,vans[1]+5<10,放在第二辆车【8,5】
3)说明载重8也是可以的,此时最小载重为7,最大载重8;继续二分:7+8/2=7,假定载重为7;遍历货物列表:
Weight=2,遍历货车数组【0,0】;因为vans[0]+2<7,放在第一辆车【2,0】;
Weight=3,遍历货车数组【2,0】;因为vans[0]+3<7,放在第一辆车【5,0】;
Weight=3,遍历货车数组【5,0】;因为vans[0]+3>7,vans[1]+5<7,放在第一辆车【5,3】;
Weight=5,遍历货车数组【8,0】;因为vans[0]+5>10,vans[1]+5>7,说明无法满足条件,进行回退;回退到第一次遍历的第一个循环【2,0】:开启第二次遍历的第一个循环,Weight=3,我们尝试将其放入第二辆车【2,3】;
Weight=3,遍历货车数组【2,3】;因为vans[0]+3<7,放在第一辆车【5,3】;
Weight=5,遍历货车数组【5,3】;因为vans[0]+5>7,vans[1]+5>7,说明无法满足条件,进行回退;回退到第二次遍历的第一个循环【2,3】:开启第三次遍历的第一个循环,Weight=3,我们尝试将其放入第二辆车【2,6】;
Weight=5,遍历货车数组【2,6】;因为vans[0]+5<=7,放在第一辆车【7,6】
3、最终结果为7
以上就是大体的解题思路,可能比较难懂,大家可以debug一下代码多尝试理解一下!这道题本身是比较难的,正确率也低,目前没有看到满分的!
代码实现一:
package com.codernav.demo.hwod.exam; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Scanner; /** * @title 统一限载货物数最小值 * @Description 火车站附近的货物中转站负责将到站货物运往仓库,小明在中转站负责调度2K辆中转车(K辆干货中转车,K辆湿货中转车)。 * 货物由不同供货商从各地发来,各地的货物是依次进站,然后小明按照卸货顺序依次装货到中转车上, * 一个供货商的货只能装到一辆车上,不能拆装,但是一辆车可以装多家供货商的货; * 中转车的限载货物量由小明统一制定,在完成货物中转的前提下,请问中转车的统一限载货物数最小值为多少。 * @Author 开发者导航 * @website https://codernav.com * @date 2023/5/28 */ public class Main { public static int k; public static void main(String[] args) { Scanner sc = new Scanner(System.in); int len = sc.nextInt(); int[] goods = new int[len]; for (int i = 0; i < len; i++) { goods[i] = sc.nextInt(); } int[] types = new int[len]; for (int i = 0; i < len; i++) { types[i] = sc.nextInt(); } k = sc.nextInt(); List<Integer> listDry = new ArrayList<>(); //干货物 List<Integer> listWet = new ArrayList<>(); //湿货物 int countDry = 0; //干货物总重 int countWet = 0; //湿货物总重 for (int i = 0; i < len; i++) { int type = types[i]; int good = goods[i]; if (type == 0) { listDry.add(good); countDry += good; } else { listWet.add(good); countWet += good; } } Collections.sort(listDry); Collections.sort(listWet); int minDry = 0; int minWet = 0; if (listDry.size() != 0) { minDry = handle(listDry, countDry); } if (listWet.size() != 0) { minWet = handle(listWet, countWet); } int res = Math.max(minDry, minWet); System.out.println(res); } /** * 求出最小货物限载量 * * @param goodList 货物集合 * @param count 货物总重 * @return */ public static int handle(List<Integer> goodList, int count) { //最重货物 int maxList = goodList.get(goodList.size() - 1); //平均每辆车放置的最低重量 int minWeight = count % k == 0 ? count / k : count / k + 1; //最少限载货物量 int min = Math.max(maxList, minWeight); //最大限载货物量(一辆车的时候) int max = count; //二分法 while (min < max) { int mid = (min + max) / 2; //K辆车(每次都需要初始化) int[] vans = new int[k]; if (check(goodList, 0, vans, mid)) { max = mid; } else { min = mid + 1; } } return min; } /** * 判断当前限载货物量是否能装完货物 * * @param goods 货物集合 * @param index 货物索引 * @param vans 货车数组 * @param weight 限载货物量 * @return */ public static boolean check(List<Integer> goods, int index, int[] vans, int weight) { // index == nums.length说明都放完了 if (index == goods.size()) { return true; } for (int i = 0; i < vans.length; i++) { //多辆车货物重量一样,前面已经试了不要重复试,此处可能不好理解 if (i > 0 && vans[i] == vans[i - 1]) { continue; } // 满足条件才能放入 if (vans[i] + goods.get(index) <= weight) { // 放入 vans[i] = vans[i] + goods.get(index); // 后续递归放入剩余的货物 if (check(goods, index + 1, vans, weight)) { return true; } //上面的策略失败了,就回退,继续尝试后面的策略 vans[i] = vans[i] - goods.get(index); } } return false; } }
代码实现二:Java代码满分实现
package com.codernav.demo.hwod.exam; import java.util.ArrayList; import java.util.List; import java.util.Scanner; /** * @title 统一限载货物数最小值 * @Description 火车站附近的货物中转站负责将到站货物运往仓库,小明在中转站负责调度2K辆中转车(K辆干货中转车,K辆湿货中转车)。 * 货物由不同供货商从各地发来,各地的货物是依次进站,然后小明按照卸货顺序依次装货到中转车上, * 一个供货商的货只能装到一辆车上,不能拆装,但是一辆车可以装多家供货商的货; * 中转车的限载货物量由小明统一制定,在完成货物中转的前提下,请问中转车的统一限载货物数最小值为多少。 * @Author 开发者导航 * @website https://codernav.com * @date 2023/5/28 */ public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int length = sc.nextInt(); int[] goods = new int[length]; int[] types = new int[length]; for (int i = 0; i < length; i++) { goods[i] = sc.nextInt(); } for (int i = 0; i < length; i++) { types[i] = sc.nextInt(); } int k = sc.nextInt(); int minGan = 0; int maxGan = 0; int minShi = 0; int maxShi = 0; List<Integer> ganGoods = new ArrayList<>(); List<Integer> shiGoods = new ArrayList<>(); for (int i = 0; i < length; i++) { if (types[i] == 0) { minGan = Math.max(goods[i], minGan); maxGan += goods[i]; ganGoods.add(goods[i]); } else { minShi = Math.max(minShi, goods[i]); maxShi += goods[i]; shiGoods.add(goods[i]); } } if (k == 1) { System.out.println(Math.max(maxGan, maxShi)); } else if (k >= Math.max(ganGoods.size(), shiGoods.size())) { System.out.println(Math.max(minGan, minShi)); } else { int minL = Math.max(minShi, minGan); int maxL = Math.max(maxGan, maxShi); while (minL <= maxL) { int li = (maxL + minL) / 2; if (candiv(li, length, ganGoods, shiGoods, k)) { maxL = li - 1; } else { minL = li + 1; } } System.out.println(minL); } } private static boolean candiv(int li, int length, List<Integer> ganGoods, List<Integer> shiGoods, int k) { int gCarCnt = 0; int sCarCnt = 0; int gSum = 0; int sSum = 0; if (div(li, ganGoods, k, gCarCnt, gSum)) { return false; } if (div(li, shiGoods, k, sCarCnt, sSum)) { return false; } return true; } private static boolean div(int li, List<Integer> goods, int k, int sCarCnt, int sSum) { for (Integer good : goods) { if (sSum + good <= li) { sSum += good; } else { if (sCarCnt + 1 == k) { return true; } else { sCarCnt += 1; sSum = good; } } } return false; } }