华为在线笔试题 - n个任务,m个执行机器求最小时间的升级版问题

题目

华为在线笔试题 - n个任务,m个执行机器求最小时间的升级版问题_第1张图片
华为在线笔试题 - n个任务,m个执行机器求最小时间的升级版问题_第2张图片

问题分解

华为这道题出的比较难,问题不仅涉及动态规划,更涉及到后续洗杯子的问题。
所以解题分为两部分:

  1. 通过动态规划,计算每个咖啡机锁需要煮的咖啡数目
  2. 通过某种策略,计算洗杯子所需要的最小时间

动态规划求解咖啡机的任务分配

动态规划的两大要点 ==》

  1. 定义子问题的形式
  2. 定义在所有子问题上通用的处理逻辑

子问题的形式

在m个咖啡机的前提下,由j(1<=j<=n)来唯一的定义一个子问题。

处理逻辑

当j等于1时,我们必然选择生产速度最快的咖啡机
当j>1时,我们已知j-1时最小化生产时间的任务分配计划,我们计算每一台咖啡机增加一杯咖啡所后需要花费的总时间,然后我们选择总时间最小的那一个。当总时间相等时,选择生产速度快的那台。

实现方式

在处理逻辑这一小节中,我们看出来,在每个子问题中,我们都只需要选择最优的那一台咖啡机。
在这种情况下,我们使用堆排序的方式,将大大减小选择时间。
我们定义了一个子类,用来描述咖啡机的任务数,工作速度,索引编号,该咖啡机生产的咖啡中已清洗的杯子数。
按照处理逻辑中的选择方式重新定义了子类的compareTo方法,实现堆排序,不断选择最优的咖啡机,对其任务信息进行增加,直到j==n为止。

贪心策略,计算洗杯子所需要的最小时间

这里我们选择了贪心策略来解决这一问题,由于是笔试完之后想出来的,所以没有在线上测试。后经过同学提醒,这种策略,在某种情况下回出错。因为贪心策略只是求解局部最优,而非全局最优。

本文中采取的策略是,根据第一步中生成的任务分配信息,从t=0开始计算下一个生成的咖啡时间,然后计算当前使用咖啡机更快,还是任其自由风干更快,如果使用咖啡机则需要改变咖啡机的可用时间。

代码

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n, m, x, y;
        int num = sc.nextInt();
        String noUse = sc.nextLine();

        int[] results = new int[num];
        int idx = 0;
        while (num > 0){
            num--;
            String firstLine = sc.nextLine();
            String[] nums = firstLine.split(" ");
            n = Integer.valueOf(nums[0]);
            m = Integer.valueOf(nums[1]);
            x = Integer.valueOf(nums[2]);
            y = Integer.valueOf(nums[3]);

            int[] V = new int[m];
            for (int i=0;i<m;i++){
                V[i] = sc.nextInt();
            }
            noUse = sc.nextLine();
            int[] temp = new int[n+1];
            temp[0] = x;
            for (int i = 1; i < temp.length; i++) {
                temp[i] = y;
            }
            results[idx++] = getRes(n,m,x,y,V);
        }

        for (int i = 0; i < results.length; i++) {
            System.out.print(results[i]);
            if (i!=results.length-1){
                System.out.println();
            }
        }

    }

    /**
     *
     * @param n: 任务数,在本题中为需要咖啡的人数
     * @param m: 机器数,在本题中为咖啡机的个数
     * @param x: 洗杯机每洗一只杯子需要的时间
     * @param y: 每个人手动洗杯子需要的时间
     * @param V:每台机器完成任务所需的时间
     * @return 所有人喝完咖啡所需的最小时间
     */
    public static int getRes(int n,int m, int x, int y, int[] V){
        int washMathineFinishTime=-1;
        int washAllFinishTime=0;

        //step1: 初始化,每台机器的任务情况,初始任务数都为0
        taskInfo[] taskInfos = new taskInfo[m];
        for (int i = 0; i < m; i++) {
            taskInfos[i] = new taskInfo(V[i], i);
        }

        //step2: 计算能让每个人都最快喝上coffee的分配计划
        MinHeap.buildHeap(taskInfos);
        MinHeap.heapSize = m;
        for (int i = 0; i < n; i++) {
            taskInfos[0].taskNumber+=1;
            MinHeap.doHeapify(taskInfos, 1);
        }

        System.out.println("分配之后的任务信息: ");
        for (int i = 0; i < m; i++) {
            System.out.println(taskInfos[i]);
        }
		
		//step3: 计算洗杯子的最小时间
        boolean isWashFinish = false;
        while (true){
            isWashFinish = true;
            int earlistTime = Integer.MAX_VALUE;
            int index=0;
            for (int i = 0; i < taskInfos.length; i++) {
                if (taskInfos[i].hasWashed<taskInfos[i].taskNumber){
                    isWashFinish = false;
                    if((taskInfos[i].hasWashed+1)*taskInfos[i].taskTime < earlistTime){
                        earlistTime = (taskInfos[i].hasWashed+1)*taskInfos[i].taskTime;
                        index = i;
                    }
                }

            }
            if (isWashFinish) return washAllFinishTime;

            taskInfos[index].hasWashed += 1;
            if (washMathineFinishTime<0){
                if (x < y){
                    washMathineFinishTime = earlistTime+x;
                    washAllFinishTime = earlistTime+x;
                }else{
                    washAllFinishTime = earlistTime + y;
                }
            }else{
                if ((washMathineFinishTime+x)<earlistTime+y){
                    washMathineFinishTime = washMathineFinishTime + x;
                    washAllFinishTime = washMathineFinishTime;
                }else {
                    washAllFinishTime = earlistTime+y;
                }
            }

        }

    }

    static class MinHeap{
        static int heapSize=0;

        static int leftChild(int i){
            return 2*i;
        }
        static int rightChild(int i){
            return 2*i+1;
        }
        static void buildHeap(taskInfo[] data){
            for (int i = data.length/2; i >= 1; i--) {
                doHeapify(data, i);
            }
        }
        static void doHeapify(taskInfo[] data, int index){
            int leftIndex = leftChild(index);
            int rightIndex = rightChild(index);
            int minIndex;
            if (leftIndex<=heapSize && data[index-1].compareTo(data[leftIndex-1]) > 0){
                minIndex = leftIndex;
            }else{
                minIndex = index;
            }
            if (rightIndex<=heapSize && data[minIndex-1].compareTo(data[rightIndex-1]) > 0){
                minIndex = rightIndex;
            }
            if (minIndex != index){
                taskInfo temp = data[minIndex-1];
                data[minIndex-1] = data[index-1];
                data[index-1] = temp;

                doHeapify(data, minIndex);
            }
        }

    }
    static class taskInfo implements Comparable<taskInfo>{
        int taskNumber = 0;
        int taskTime;
        int taskIndex;
        int hasWashed = 0;
        taskInfo(int time, int idx){
            taskTime = time;
            taskIndex = idx;
        }

        @Override
        public int compareTo(taskInfo info2) {
            if (((info2.taskNumber+1)*info2.taskTime > (this.taskNumber+1)*this.taskTime) ||
                    ((info2.taskNumber+1)*info2.taskTime == (this.taskNumber+1)*this.taskTime && info2.taskTime>this.taskTime)){
                return -1;
            }
            return 1;
        }

        @Override
        public String toString() {
            return "taskIndex: " + taskIndex + " taskTime: " + taskTime + " taskNumber: " + taskNumber +" hasWashed: " + hasWashed;
        }
    }
}


你可能感兴趣的:(算法总结,动态规划)