题目:给一个整数数组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;
}
}