【刷题篇】喝咖啡洗杯子问题

一、题目

给定一个数组arr,arr[i]代表第i号咖啡机泡一杯咖啡的时间,给定一个整数N,表示有N个人正在等着泡咖啡,每台咖啡机只能轮流泡咖啡,其次,只有一台可以洗咖啡杯的机器,一次只能洗一个咖啡杯,时间耗费a,洗完才能洗下一杯,每个咖啡杯也可以自己挥发干净,时间消耗b,咖啡杯可以并行挥发,假设所有人拿到咖啡后立刻喝完,返回从开始等待到所有咖啡杯都变干净的最短时间,给定3个参数,int[] arr,int a,int b,int N

二、题目分解

将题目分解成两大步骤来做:

2.1. 求出N个人喝完咖啡的最快时间,存储在数组中

在这里插入图片描述

 public static class Machine{
      public int timePoint;
      public int workTime;
      public Machine(int t,int w){
          this.timePoint=t;

          this.workTime=w;
      }

    }
    public static class MachineComparator implements Comparator<Machine>{

        @Override
        public int compare(Machine o1, Machine o2) {
            return (o1.timePoint+o1.workTime)-(o2.timePoint+o2.workTime);
        }
    }


    public int minTime2(int[] arr,int n,int a,int b){

        PriorityQueue<Machine> heap=new PriorityQueue<Machine>(new MachineComparator() );
        for (int i = 0; i <arr.length ; i++) {
            heap.add(new Machine(0,arr[i]));
        }
        int[] drinks=new int[n];
        for (int i = 0; i < n; i++) {
            Machine cur=heap.poll();
            cur.timePoint+= cur.workTime;
            drinks[i]= cur.timePoint;
            heap.add(cur);
        }
        return bestTime(drinks,a,b,0,0);
     }

2.2 求出洗完全部咖啡杯的最短时间

2.2.1 方法一:递归尝试

递归函数:
在这里插入图片描述
参数说明:

drinks 每一个人喝完的时间 wash 洗一杯需要的时间 air 自然挥发的时间
drinks[0,…index]下标已经洗干净了,不用管了 drinks[index…]所需的最短时间点返回 free
洗咖啡杯机器可再次使用的时间

终止条件:

index==drinks.length ,说明所有的杯子都洗干净了,直接返回0

普遍情况:
index号杯子有两种选择
(1)通过洗咖啡杯的机器清洗

开始洗的时间由,index喝完的时间和洗咖啡杯机器的可再用时间两者之间较大者决定,例如:index在7时间喝完咖啡,但洗咖啡杯的机器可在用的时间是10,那么index的杯子只能从10才能开始洗,反之,因为是同样的道理

除了index号杯子剩下杯子全部便干净的时间通过递归求出,因为index杯子使用洗咖啡的机器清晰,故下一次可在用的时间是index清洗干净了的时间

该情况下,所有杯子都变干净的的时间是,index变干净的时间和剩下所有杯子都变干净的时间的较大值

(2)自然挥发

index变干净的时间==喝完的时间+挥发的时间

剩下的杯子都变干净的时间,调用递归

该情况下,所有杯子都变干净的的时间是,index变干净的时间和剩下所有杯子都变干净的时间的较大值

返回两种选择所需时间的较小值

2.2.2 动态规划

业务限制模型,因为对于free这个参数的范围,我们无法直观得到。这时我们需要自己估计出来free的大小,通过分心我们直到,当所有的杯子都决定去洗时,此时的free将取到最大值.

   public static int bestTimeDp(int[] drinks,int wash,int air){
        int N= drinks.length;
        int maxFree=0;
        for (int i = 0; i < drinks.length; i++) {
            maxFree=Math.max(maxFree,drinks[i])+wash;

        }
        int[][] dp= new int[N+1][maxFree+1];
        //dp[N][...]=0;   (index==drinks.length) return 0;

        for(int index=N-1;index>=0;index--){

            for(int free=0;free<=maxFree;free++){

                int selfClean1=Math.max(drinks[index],free)+wash;
                if(selfClean1>maxFree){
                    continue;
                }
                int restClean1=dp[index+1][selfClean1];
                int p1= Math.max(selfClean1,restClean1);

                //index号杯子决定挥发
                int selfClean2=drinks[index]+air;
                int restClean2=dp[index+1][free];
                int p2=Math.max(selfClean2,restClean2);
                dp[index][free]=Math.max(p1,p2);
            }
        }
        return dp[0][0];

    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值