一眼就感觉是dfs爆搜,肯定超时,正解应该是递归回溯+二分+剪枝(做不来hhh)
超时版本:
class Solution {
public:
//第一个参数是当前处理到的工作数量,第二个参数是当前所有人中的最大工作时间
void dfs(int u,int maxn,vector<int>& jobs,int k){
//剪枝
if(maxn >= res) return;//当前已经不可能成为最优解了
//递归边界,因为max此时一定小于res,所以只要处理完所有任务,可以直接更新res
if(u == jobs.size()){
res = maxn;
return;
}
//让每个人处理当前工作看看
//所以遍历的是人,让第i个人处理当前这份工作后,再考虑下一份工作谁来处理,可能还是当前人处理,因为从0开始遍历人
for(int i = 0; i < k; ++i){
sum[i] += jobs[u];
dfs(u + 1,max(sum[i],maxn),jobs,k);
//记得回溯
sum[i] -= jobs[u];
}
}
int minimumTimeRequired(vector<int>& jobs, int k) {
//dfs爆搜版本
sum.resize(k);
dfs(0,0,jobs,k);
return res;
}
private:
int res = INT_MAX;
vector<int> sum;//sum[i]记录每个员工的工作时间
};
正解:
class Solution {
public:
bool backtrack(vector<int>& jobs, vector<int>& workloads, int idx, int limit) {
if (idx >= jobs.size()) {
return true;
}
int cur = jobs[idx];
for (auto& workload : workloads) {
if (workload + cur <= limit) {
workload += cur;
if (backtrack(jobs, workloads, idx + 1, limit)) {
return true;
}
workload -= cur;
}
// 如果当前工人未被分配工作,那么下一个工人也必然未被分配工作
// 或者当前工作恰能使该工人的工作量达到了上限
// 这两种情况下我们无需尝试继续分配工作
if (workload == 0 || workload + cur == limit) {
break;
}
}
return false;
}
bool check(vector<int>& jobs, int k, int limit) {
vector<int> workloads(k, 0);
return backtrack(jobs, workloads, 0, limit);
}
int minimumTimeRequired(vector<int>& jobs, int k) {
sort(jobs.begin(), jobs.end(), greater<int>());
int l = jobs[0], r = accumulate(jobs.begin(), jobs.end(), 0);
while (l < r) {
int mid = (l + r) >> 1;
if (check(jobs, k, mid)) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
}
};