百度&必应权4, 日IP8000. 查看详情
自助收录

2023年华为OD机考真题:统一限载货物数最小值

算法刷题2年前 (2023)更新 江南白衣
482 0 0
2023年华为OD机考真题:统一限载货物数最小值

全网最全面的华为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;
    }
}

 

© 版权声明

相关文章

暂无评论

暂无评论...