1. 题目来源
2. 题目解析
本题正解应该是状压 dp
,但由于好久好久没弄困难的 dp
问题了,手太生。这个 n
又这么小,还是暴搜会比较香。
每个数两种情况,要么加到现有组中,要么自成一组。也快到临界值了,得加上剪枝优化,dfs()
参数存一个最大值,不要自己循环求最大值这妥妥超时,也不要用 min()
来更新最大值,这样就不是剪枝了。当传递的参数最大值还没全局最大值小的时候,后面的情况都不需要再考虑了,直接 return
即可,加上剪枝优化后速度直接飞起。
- 时间复杂度: O ( 不 会 分 析 ) O(不会分析) O(不会分析)。
- 空间复杂度: O ( 不 会 分 析 ) O(不会分析) O(不会分析)
代码:
class Solution {
public:
vector<int> jobs; // 全局数据,方便传参
vector<int> s; // 集合,分配给 k 个工人,每个工人分配的工作总时间
int res = 1e9; // 全局最大值
// 需要记录最大值,不能循环来求,否则时间复杂度会变成 10^7,超时
void dfs(int a, int b, int c) { // 枚举到第a项工作,当前有b组,当前方案的最大时间为c
if (c > res) return ; // 这个优化很重要,如果当前最大工作时间已经大于全局的 res, 则可以直接 return 当前部分做剪枝
if (a == jobs.size()) {
res = c;
return ;
}
for (int i = 0; i < b; i ++ ) { // 分到现有组中
s[i] += jobs[a];
dfs(a + 1, b, max(c, s[i]));
s[i] -= jobs[a]; // 恢复现场
}
if (b < s.size()) { // 自成新组,但不能超过限制组数
s[b] = jobs[a];
dfs(a + 1, b + 1, max(c, s[b]));
s[b] = 0;
}
}
// n 个任务分成 k 个不同的非空子集,斯特林数,大约是 130w 计算量,可以直接暴搜
int minimumTimeRequired(vector<int>& _jobs, int k) {
jobs = _jobs;
s.resize(k); // 最多分 k 组,分给 k 个工人
dfs(0, 0, 0);
return res;
}
};