• 所有人喝完咖啡并洗完咖啡杯,至少来到时间点


    问题描述:

            数组arr代表每一个咖啡机冲一杯咖啡的时间,每个咖啡机只能串行的制造咖啡。现在有n个人需要喝咖啡,只能用咖啡机来制造咖啡。认为每个人喝咖啡的时间非常短,冲好的时间即是喝完的时间。每个人喝完之后咖啡杯可以选择洗或者自然挥发干净,只有一台洗咖啡杯的机器,只能串行的洗咖啡杯。洗杯子的机器洗完一个杯子时间为a,任何一个杯子自然挥发干净的时间为b。
            四个参数:arr, n, a, b
            假设时间点从0开始,返回所有人喝完咖啡并洗完咖啡杯的全部过程结束后,至少来到什么时间点。

    思路一:暴力尝试法

    代码:

    1. /**
    2. *
    3. * @param arr 每一个咖啡机冲一杯咖啡的时间
    4. * @param n n个人需要喝咖啡
    5. * @param a 洗完一个杯子时间为a
    6. * @param b 任何一个杯子自然挥发干净的时间为b
    7. * @return 所有人喝完咖啡并洗完咖啡杯的全部过程结束后,至少来到什么时间点
    8. */
    9. public static int minTime1(int[] arr,int n ,int a,int b){
    10. //用于记录每台咖啡机目前来到的时间点
    11. int[] times = new int[arr.length];
    12. //记录每个人拿到咖啡时的时间
    13. int[] drink = new int[n];
    14. return forceMake(arr,times,0,drink,n,a,b);
    15. }
    16. /**
    17. *
    18. * @param arr 每一个咖啡机冲一杯咖啡的时间
    19. * @param times 用于记录每台咖啡机目前来到的时间点
    20. * @param kth 记录目前是第几号咖啡机
    21. * @param drink 记录每个人拿到咖啡时的时间
    22. * @param n n个人需要喝咖啡
    23. * @param a 洗完一个杯子时间为a
    24. * @param b 任何一个杯子自然挥发干净的时间为b
    25. * @return 主要是冲咖啡流程,返回给洗咖啡杯流程每杯咖啡冲好的时间 所有人喝完咖啡并洗完咖啡杯的全部过程结束后,至少来到什么时间点
    26. *
    27. * (每个人暴力尝试用每一个咖啡机给自己做咖啡)
    28. */
    29. public static int forceMake(int[] arr,int[] times,int kth,int[] drink,int n,int a,int b){
    30. if (kth == n){// kth 从0开始遍历,到n结束,所有的信息都收集完成,即冲咖啡结束,开始洗咖啡杯
    31. int[] drinkSorted = Arrays.copyOf(drink,kth);
    32. Arrays.sort(drinkSorted);
    33. return forceWash(drinkSorted,a,b,0,0,0);
    34. }
    35. //当前咖啡机未遍历到第n个人
    36. int time = Integer.MAX_VALUE;
    37. for (int i = 0;i//遍历每一台咖啡机
    38. int work = arr[i];//咖啡机冲一杯咖啡时间
    39. int pre = times[i];//咖啡机此时到达可以冲咖啡的时间
    40. //若选择这台咖啡机给第 kth 个人冲咖啡,设置好第 kth 个人拿到咖啡的时间和当前咖啡机到达的工作时间点。
    41. drink[kth] = pre + work;
    42. times[i] = pre+work;
    43. //查看后续过程全部完成至少来到的时间点
    44. time = Math.min(time,forceMake(arr,times,kth+1,drink,n,a,b));
    45. //回溯过程
    46. drink[kth] = 0;
    47. times[i] = pre;
    48. }
    49. return time;
    50. }
    51. /**
    52. *
    53. * @param drinks 每个人拿到咖啡时的时间点
    54. * @param a 洗完一个杯子时间为a
    55. * @param b 任何一个杯子自然挥发干净的时间为b
    56. * @param index 目前到了第index个人冲洗咖啡杯
    57. * @param washLine 洗杯子的机器目前来的时间点
    58. * @param time 全部完成工作至少的时间点
    59. * @return 全部完成至少来到的时间点
    60. */
    61. public static int forceWash(int[] drinks,int a,int b,int index,int washLine,int time){
    62. //全部人的咖啡杯都洗完
    63. if (index == drinks.length){
    64. return time;
    65. }
    66. //咖啡杯没有洗完
    67. //选择一:当前index号咖啡杯选择用洗咖啡杯机器清洗
    68. int wash = Math.max(drinks[index],washLine)+a;//冲好咖啡时间和洗咖啡杯机器能工作时间取最大值
    69. int ans1 = forceWash(drinks,a,b,index+1,wash,Math.max(wash,time));//完成后序过程,取得至少得时间
    70. //选择二:当前index号咖啡杯选择用自然挥发
    71. int dry = drinks[index]+b;
    72. int ans2 = forceWash(drinks,a,b,index+1,washLine,Math.max(dry,time));
    73. //选取两种情况中时间点早的返回
    74. return Math.min(ans1,ans2);
    75. }

    思路二:在思路一得基础上,使用小根堆来优化冲咖啡的过程。

    代码:

    1. /**
    2. * 小根堆的节点,用于表示每一台咖啡机
    3. * timePoint 咖啡机当前可以工作的时间点
    4. * workTime 咖啡机每次冲一杯咖啡的时间
    5. */
    6. public static class Machine{
    7. public int timePoint;
    8. public int workTime;
    9. public Machine(int t,int w){
    10. timePoint = t;
    11. workTime = w;
    12. }
    13. }
    14. /**
    15. * 比较器】
    16. * 小根堆
    17. * 当咖啡机当前工作时间和冲一杯咖啡时间和最小时,优先使用
    18. */
    19. public static class MachineComparator implements Comparator{
    20. @Override
    21. public int compare(Machine o1, Machine o2) {
    22. return (o1.timePoint+o1.workTime)-(o2.workTime+o2.timePoint);
    23. }
    24. }
    25. /**
    26. * 每个人暴力尝试用每一个咖啡机给自己做咖啡,优化成贪心
    27. * @param arr 每一个咖啡机冲一杯咖啡的时间
    28. * @param n n个人需要喝咖啡
    29. * @param a 洗完一个杯子时间为a
    30. * @param b 任何一个杯子自然挥发干净的时间为b
    31. * @return 全部完成至少来到的时间点
    32. */
    33. public static int minTime2(int[] arr,int n, int a, int b){
    34. PriorityQueue heap = new PriorityQueue<>(new MachineComparator());
    35. for (int i =0;i
    36. heap.add(new Machine(0,arr[i]));
    37. }
    38. int[] drinks = new int[n];
    39. for (int i =0;i
    40. //小根堆堆顶始终是使用当前咖啡机时最优的答案
    41. Machine cur = heap.poll();
    42. cur.timePoint += cur.workTime;
    43. drinks[i] = cur.timePoint;
    44. heap.add(cur);
    45. }
    46. //洗杯子阶段
    47. return process(drinks,a,b,0,0);
    48. }
    49. /**
    50. *
    51. * @param drinks 记录每个人拿到咖啡时的时间
    52. * @param a 洗完一个杯子时间为a
    53. * @param b 任何一个杯子自然挥发干净的时间为b
    54. * @param index 目前是index个人
    55. * @param washLine drinks[index....],洗杯子的机器什么时候可以接受新的杯子
    56. * @return 全部完成至少来到的时间点
    57. */
    58. public static int process(int[] drinks,int a,int b,int index,int washLine){
    59. //只剩一个杯子的时候
    60. if (index==drinks.length-1){
    61. return Math.min(Math.max(washLine,drinks[index])+a,drinks[index]+b);
    62. }
    63. //不止一个杯子
    64. //wash是我当前的咖啡杯,洗完的时间
    65. //选择洗
    66. int wash = Math.max(washLine,drinks[index])+a;// 洗完我这一杯,时间来到哪
    67. int next1 = process(drinks,a,b,index+1,wash);
    68. int p1 = Math.max(wash,next1);
    69. //选择挥发
    70. int dry = drinks[index]+b;// 挥发完我这一杯,时间来到哪
    71. int next2 = process(drinks,a,b,index+1,washLine);
    72. int p2 = Math.max(dry,next2);
    73. return Math.min(p1,p2);
    74. }

    思路三:思路二的基础上使用动态规划

    代码:

    1. /**
    2. * 把方法二洗咖啡杯的暴力尝试进一步优化成动态规划
    3. * @param arr 每一个咖啡机冲一杯咖啡的时间
    4. * @param n n个人需要喝咖啡
    5. * @param a 洗完一个杯子时间为a
    6. * @param b 任何一个杯子自然挥发干净的时间为b
    7. * @return 全部完成至少来到的时间点
    8. */
    9. public static int minTime3(int[] arr,int n,int a,int b){
    10. PriorityQueue heap = new PriorityQueue<>(new MachineComparator());
    11. for (int i =0;i
    12. heap.add(new Machine(0,arr[i]));
    13. }
    14. int[] drinks = new int[n];
    15. for (int i =0;i
    16. Machine cur = heap.poll();
    17. cur.timePoint += cur.workTime;
    18. drinks[i] = cur.timePoint;
    19. heap.add(cur);
    20. }
    21. //当洗杯子时间大于挥发时间时,所有的杯子全部采用挥发方式
    22. if (a>=b){
    23. return drinks[n-1]+b;
    24. }
    25. //二维数组dp 行表示每一个杯子 列表示每一个时间点(最大的时间点为最后一杯咖啡冲好后,用机器清洗杯子)、
    26. //dp[i][j] 表示从第i个杯子到最后一个杯子,开始时间点为j,最早结束的时间
    27. int[][] dp = new int[n][drinks[n-1]+n*a];
    28. //二维数组的最后一行表示只剩下最后一个杯子需要清洗时的情况
    29. for (int i =0;i0].length;i++){
    30. dp[n-1][i] = Math.min(
    31. Math.max(i,drinks[n-1])+a,
    32. drinks[n-1]+b
    33. );
    34. }
    35. //二维数组的普遍位置
    36. for (int row = n-2;row>=0;row--){
    37. int washLine = drinks[row] + (row+1)*a;
    38. for (int col =0;col
    39. int wash = Math.max(col,drinks[row])+a;
    40. dp[row][col] = Math.min(
    41. Math.max(wash,dp[row+1][wash]),
    42. Math.max(drinks[row]+b,dp[row+1][col])
    43. );
    44. }
    45. }
    46. return dp[0][0];
    47. }

    测试代码

    1. public static int[] randomArray(int len,int max){
    2. int[] arr = new int[len];
    3. for (int i =0;i
    4. arr[i] = (int)(Math.random()*max)+1;
    5. }
    6. return arr;
    7. }
    8. public static void printArray(int[] arr){
    9. System.out.print("arr : ");
    10. for (int j =0;j
    11. System.out.print(arr[j]+" , ");
    12. }
    13. System.out.println();
    14. }
    15. public static void main(String[] args) {
    16. int len = 5;
    17. int max = 9;
    18. int testTime = 50000;
    19. System.out.println("test begin!");
    20. for (int i =0;i
    21. int[] arr = randomArray(len,max);
    22. int n = (int)(Math.random()*5)+1;
    23. int a = (int)(Math.random()*5)+1;
    24. int b = (int)(Math.random()*10)+1;
    25. int ans1 = minTime1(arr,n,a,b);
    26. int ans2 = minTime2(arr,n,a,b);
    27. int ans3 = minTime3(arr,n,a,b);
    28. if (ans1!=ans2 || ans3!=ans1){
    29. System.out.println("Oops!");
    30. printArray(arr);
    31. System.out.println("ans1 : " + ans1);
    32. System.out.println("ans2 : " + ans2);
    33. System.out.println("ans3 : " + ans3);
    34. }
    35. }
    36. System.out.println("test end!");
    37. }

  • 相关阅读:
    链接装载与库:第八章——Linux共享库组织
    Polygon zkEVM的Dragon Fruit和Inca Berry升级
    4.迭代最近点ICP及非线性优化求解
    html中字体加粗
    webpack react npm start报错解决 ERR_OSSL_EVP_UNSUPPORTED
    QT QChartView 鼠标随动 十字线
    会话管理(Cookie和Session)知识点总结-DX的笔记
    直播预告 | 博睿学院 Bonree ONE接入zabbix数据源提高可观测运维能力
    Alexa智能家居构建技能教程(官网版翻译=保姆级)
    Git命令总结-常用-后续使用频繁的再添加~
  • 原文地址:https://blog.csdn.net/z1171127310/article/details/128135813