完成所有工作的最短时间

2021-05-08  本文已影响0人  张隐蔽

题目:给一个整数数组jobs,其中jobs[i]是完成第 i 项工作要花费的时间。

现在需要将这些工作分配给 k 位工人,所有的工作都应该分配完成,且每项工作只能分配给一个人,工人的工作时间是完成分配给他们的工作的的时间总和。现要求设计一套方案,使工人的最大工作时间得以最小化。即尽可能早的完成所有工作,并求出这个时间。

1、暴力求解,回溯算法经典模版

private void backTrack("原始参数") {
    
    if ("终止条件") {
      return;
    }
   
    for (int j = "循环开始初始值"; j < "循环条件"; j++) {
      
      // 作出选择
      backTrack("新的参数");
      // 撤销选择
    }
  }

每份工作都有 K 种分配方案,求出每一种情况下的时间并记录下来,得出一个最小值。
思路:一共n份工作,每份工作都有可能分配给k个人,链式分配工作

 // 尽可能小的最大工作时间
  int res = Integer.MAX_VALUE;
 /**
   * @param jobs     工作的集合
   * @param jobIndex 当前处理的工作下标
   * @param worker   工人当前的工作情况
   * @param max      worker数组的最大值
   */
  private void backTrack(int[] jobs, int jobIndex, int[] worker, int max) {
    // 如果前面已经得出的res 比传进来的max小,那么就可以忽略本次计算
    // 因为当前已经分配的工作中工人的工作最大值max大于之前得出的最优解, 
    // 后续的工作无论怎么分配都不可能是最优解
    if (max >= res)return;
    // 如果已经处理到了最后一项工作 那么这个时候 记录一下当前的 尽可能小的最大工作时间
    // 取已经求出来的res值和max的最小值
    if (jobIndex == jobs.length) {
      res = Math.min(res, max);
      return;
    }
    // 第jobIndex份工作需要消耗的时间
    int job = jobs[jobIndex];
    Set<Integer> set = new HashSet<>();
    // 分配当前工作,尝试分配给不同的工人
    for (int j = 0; j < worker.length; j++) {
      // 优化点1
      // 同一层中如果已经计算过 就可以直接跳过  比如当前worker = [3,7,6,6,8,3,9]这种情况下,第i份工作分给第三个人和第四个人情况重复 直接过滤掉一次
      if (!set.add(worker[j])) {
        continue;
      }
      // 优化点2 
      // 假如工作分配给第j号工人的时候,发现j号工人的总时间超过了之前求出的最优解
      // 这个时候后续的工作无论怎么分配都不最优,继续下一次循环,将此项工作分配给下一个人
      if (worker[j] + job >= res) {
        continue;
      }
      //将当前工作分配给 j 工人,并记录j工人的工作总时间
      worker[j] += job;
      // 继续分配下一个工作,这时候的工作worker数组重的最大值就是worker[j]和之前最大值max取最大值
      backTrack(jobs, jobIndex + 1, worker, Math.max(worker[j], max));
      // 当前工作去掉 进行下一个循环,即把当前的工作分配给下一个工人
      worker[j] -= job;
    }
  }
时间复杂度:k的n次方,n是jobs的长度
上一篇下一篇

猜你喜欢

热点阅读