package day_18;
import sun.security.util.Length;
import java.util.PriorityQueue;
/**
* 给定一个数组arr,arr[i]代表第i号咖啡机泡一杯咖啡的时间
* 给定一个正数N,表示N个人等着咖啡机泡咖啡,每台咖啡机只能轮流泡咖啡
* 只有一台可以洗咖啡杯子的机器,一次只能洗一个杯子,时间耗费a,洗完才能洗下一杯
* 每个咖啡杯也可以自己挥发干净,时间耗费b,咖啡杯可以并行挥发
* 假设所有人拿到咖啡之后立刻喝干净,
* 返回从开始等到所有咖啡机变干净的最短时间
* 三个参数:int[] arr、int N,int a、int b
* @Author huawei
* @Date 2021/5/19 12:39
* @Version 1.0
*/
public class Code03_Coffee {
public static int coffee(int [] arr,int N,int a,int b){
if(arr == null || arr.length == 0 || a <=0 || b <=0 ){
return -1;
}
// 1.首先N个人需要先排队拿到咖啡,首先得找到N个人在多个咖啡机下排队所花费的一个最小时间
// 需要准备一个小顶堆,这个小顶堆按照每个机器的可用时间+所花费时间来排序,说白了,就是我一个
// 用户使用这台咖啡机需要等多久才能拿到咖啡,那肯定我们都会选择那个等待时间最短的咖啡机,这个小顶堆就是用来做
// 这个事情的
PriorityQueue<Machine> heap = new
PriorityQueue<>((m1,m2)->{return (m1.startTime + m1.washTime) - (m2.startTime + m2.washTime);});
for(int i = 0 ; i < arr.length ; i++){
heap.add(new Machine(0,arr[i]));
}
int [] time = new int[N];
for(int i = 0 ; i < N ; i++){
Machine machine = heap.poll();
int start = machine.startTime;
int washTime = machine.washTime;
time[i] = start + washTime;
heap.add(new Machine(start + washTime ,washTime));
}
// 2.得到每一个人的拿到咖啡之后的最优时间点数之后,我们就来使用自然智慧来憋暴力递归
return process(time,a,b,0,0);
}
// drinks 每个人拿到咖啡的最优时间点
// wash 洗一个咖啡杯所消耗的时间
// air 一个咖啡杯挥发所消耗的时间
// free 洗咖啡机机器的可用时间
// 我只关心drink[0...index]这个时间段中的最优时间
public static int process(int [] drink,int wash,int air,int index,int free){
if(index == drink.length){
// base case
return 0;
}
// 分析可能性,洗咖啡杯只有两种可能性
// 1.使用机器来洗咖啡杯(串行)
// 如果使用机器来洗咖啡杯,我必须要等到机器空闲的时候才能洗,而且我也必须要等待我拿到了咖啡之后才能洗咖啡杯
// 所以两者之间求一个最大值,才是我此刻能够洗咖啡杯的时间点
int machineCleanTime = Math.max(drink[index],free) + wash;
// 然后当前的这个人洗完咖啡杯了,应该轮到下一个人洗咖啡杯了(在当前这个人占用了机器的情况下,其他人洗咖啡杯所消耗的时间)
int otherCleanTime = process(drink,wash,air,index + 1, machineCleanTime);
// 注意,要在两者之间求一个最大值,因为都是洗咖啡杯所消耗的时间,且都要完成洗咖啡杯的工作
machineCleanTime = Math.max(machineCleanTime,otherCleanTime);
// 2.让咖啡杯自己挥发(并行)
int airCleanTime = drink[index] + air;
// 并行就是不对下一个造成任何的影响
otherCleanTime = process(drink, wash, air, index + 1, free);
// 3.求两个的最小值
return Math.min(machineCleanTime,Math.max(airCleanTime,otherCleanTime));
}
// 两个可变参数
// index [0 N]
// free 不好评估,既然不好评估,就需要计算最坏情况,就是最差的情况下free的最大值是多少
public static int dp(int [] arr,int wash,int air){
if(arr == null || arr.length == 0 || wash <=0 || air <=0 ){
return -1;
}
PriorityQueue<Machine> heap = new
PriorityQueue<>((m1,m2)->{return (m1.startTime + m1.washTime) - (m2.startTime + m2.washTime);});
for(int i = 0 ; i < arr.length ; i++){
heap.add(new Machine(0,arr[i]));
}
int N = arr.length;
int [] time = new int[N];
for(int i = 0 ; i < N ; i++){
Machine machine = heap.poll();
int start = machine.startTime;
int washTime = machine.washTime;
time[i] = start + washTime;
heap.add(new Machine(start + washTime ,washTime));
}
// 需要求出机器空闲的最大时间
int maxFree = 0;
for(int i = 0 ; i < N ; i++){
maxFree = Math.max(time[i],maxFree) + wash;
}
int [][] dp = new int[N + 1][maxFree + 1];
return process2(time,air,wash,dp);
}
public static int process2(int [] drink,int air,int wash,int [][]dp){
int N = drink.length;
for(int index = N - 1; index >=0 ; index--){
for(int free = 0 ; free < dp[0].length;free++){
int machineCleanTime = Math.max(drink[index],free) + wash;
if(machineCleanTime > dp[0].length - 1){
break;
}
int otherCleanTime = dp[index + 1][machineCleanTime];
int p1 = Math.max(machineCleanTime,otherCleanTime);
int airCleanTime = drink[index] + air;
otherCleanTime = dp[index + 1][free];
int p2 = Math.max(airCleanTime,otherCleanTime);
dp[index][free] = Math.min(p1,p2);
}
}
return dp[0][0];
}
private static class Machine{
// 可以在几号时间点使用
int startTime;
// 这台咖啡机洗咖啡杯子的时间
int washTime;
public Machine(int startTime, int washTime) {
this.startTime = startTime;
this.washTime = washTime;
}
}
}
暴力递归到动态规划咖啡问题
最新推荐文章于 2023-07-27 22:07:11 发布