logologo

咖啡问题 ☕️

Nov 3, 2023

给定一个数组 Arr,Arr[i]代表第 i 号咖啡机泡一杯咖啡的时间 给定一个正数 N,表示 N 个人等着咖啡机泡咖啡,每台咖啡机只能轮流泡咖啡 只有一台咖啡机,一次只能洗一个杯子,时间耗费 a,洗完才能洗下一杯 假设所有人拿到咖啡之后立刻喝干净,返回从开始等到所有咖啡机变干净的最短时间 三个参数:int[] Arr,int N,int a,int b

暴力解(每个人都尝试泡一杯咖啡 很慢很慢)

/**
 * 纯暴力的对数器
 *
 * @param arr
 * @param n
 * @param a
 * @param b
 * @return
 */
public static int right(int[] arr, int n, int a, int b) {
  int[] times = new int[arr.length];
  int[] drink = new int[n];

  return forceMake(arr, times, 0, drink, n, a, b);
}

private static int forceMake(int[] arr, int[] times, int kth, int[] drink, int n, int a, int b) {
  if (kth == n) {
    int[] drinkSorted = Arrays.copyOf(drink, kth);
    Arrays.sort(drinkSorted);
    return forceWash(drinkSorted, a, b, 0, 0, 0);
  }
  int time = Integer.MAX_VALUE;
  for (int i = 0; i < arr.length; i++) {
    int work = arr[i];
    int pre = times[i];
    drink[kth] = pre + work;
    times[i] = pre + work;
    time = Math.min(time, forceMake(arr, times, kth + 1, drink, n, a, b));
    drink[kth] = 0;
    times[i] = pre;
  }
  return time;
}

private static int forceWash(int[] drinks, int a, int b, int index, int washLine, int time) {
  if (index == drinks.length)
    return time;
  int wash = Math.max(drinks[index], washLine) + a;
  int ans1 = forceWash(drinks, a, b, index + 1, washLine, Math.max(wash, time));

  int dry = drinks[index] + b;
  int ans2 = forceWash(drinks, a, b, index + 1, washLine, Math.max(dry, time));

  return Math.min(ans2, ans1);
}

贪心优化后的暴力

public static class Machine {
  public int timePoint;
  public int workTime;

  public Machine(int t, int w) {
    timePoint = t;
    workTime = w;
  }
}

public static int minTime1(int[] arr, int n, int a, int b) {
  PriorityQueue<Machine> heap = new PriorityQueue<Machine>(
      (o1, o2) -> (o1.timePoint + o1.workTime) - (o2.timePoint + o2.workTime));

  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);
}

/**
 * @param drinks 所有杯子可以开始洗的时间
 * @param wash   单杯洗干净的时间(串行)
 * @param air    挥发干净的时间(并行)
 * @param index
 * @param free   洗的机器什么时候可用
 * @return drinks[index.....]都变干净,最早的结束时间(返回)
 */
private static int bestTime(int[] drinks, int wash, int air, int index, int free) {
  if (index == drinks.length) {
    return 0;
  }
  // index号杯子 决定洗
  int selfClean1 = Math.max(drinks[index], free) + wash;
  int restClean1 = bestTime(drinks, wash, air, index + 1, selfClean1);
  int p1 = Math.max(selfClean1, restClean1);

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

动态规划

/**
   * 动态规划
   *
   * @param arr
   * @param n
   * @param a
   * @param b
   * @return
   */
  public static int minTime2(int[] arr, int n, int a, int b) {
    PriorityQueue<Machine> heap = new PriorityQueue<Machine>(
        (o1, o2) -> (o1.timePoint + o1.workTime) - (o2.timePoint + o2.workTime));
    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 dp(drinks, a, b);
  }

  public static int dp(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];
    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) {
          break; // 因为后面的也都不用填了
        }
        // index号杯子 决定洗
        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.min(p1, p2);
      }
    }
    return dp[0][0];
  }

Java
浙ICP备2021022773号    2022-PRESENT © ZhengKe