Part Four: Shift Scheduling
这上面是你的企业的所有班次,后面紧跟的xx美金表示你的某位员工能在这个班次创造的价值。但是这位员工一周只能工作time小时。现在你的任务是为他排班,让他能为你创造最大的价值同时不超过time小时的工作时限(不是一定要达到time小时)。
您的任务是编写一个函数 highestValueScheduleFor
,该函数接受一个包含所有可能的班次的集合以及员工允许工作的最大小时数作为输入,并返回员工应该选择哪些班次以生成最大价值的结果。在这里,Shift
是一个包含有关班次何时开始、何时结束的信息的结构体。它在头文件 Shift.h
中定义。
首先,选择一个班次并考虑如果分配给员工这个班次会发生什么情况(如果员工不能接受这个班次,要么是因为它与已经分配的班次重叠,要么是因为它会超过她的总工时限制),那么唯一的选择就是不给员工这个班次。否则,有两个选择:您可以分配给员工这个班次,或者不给员工这个班次。其中一个选项将比另一个更好,或者它们在产生的价值方面相等。您不会知道哪个选项更好,直到尝试它们,因此(递归地)探索两个选项,并报告导致更多价值的选项。
这里我也用了辅助函数
Set<Shift> help(const Set<Shift>& shifts, const Set<Shift>& ans, int maxHours) {
// 遍历完成的情况,如果没有可选的班次了,返回已经选择的班次集合
if (shifts.size() == 0) {
return ans;
}
// 从可选班次中选择第一个班次
Shift elem = shifts.first();
// sofar 是当前路线的进度,包含了已经选择的班次
Set<Shift> sofar = ans + elem;
// remaining 是剩余的可选班次,将当前选择的班次从可选班次中移除
Set<Shift> remaining = shifts - elem;
// 计算已经选择的班次的总时长
int sum = 0;
for (auto i : sofar) {
sum += lengthOf(i);
}
// 如果总时长超过了最大小时数限制,返回不包含当前班次的结果
if (sum > maxHours) {
return help(remaining, ans, maxHours);
}
// 如果当前班次与已选择的班次有重叠,返回不包含当前班次的结果
for (auto i : ans) {
if (overlapsWith(i, elem)) {
return help(remaining, ans, maxHours);
}
}
// 正常情况下,有两种选择:选择当前班次或不选择当前班次
auto x = help(remaining, sofar, maxHours); // 选择当前班次
auto y = help(remaining, ans, maxHours); // 不选择当前班次
int val1 = 0, val2 = 0;
// 计算选择班次 x 和 y 的总价值
for (auto i : x) {
val1 += valueOf(i);
}
for (auto i : y) {
val2 += valueOf(i);
}
// 返回总价值较大的结果
if (val1 >= val2) {
return x;
} else {
return y;
}
}
Set<Shift> highestValueScheduleFor(const Set<Shift>& shifts, int maxHours) {
// 检查 maxHours 是否为负数,如果是则报错并返回空集合
if (maxHours < 0) {
error("error: maxHours < 0");
return {};
} else if (maxHours == 0) {
// 如果 maxHours 为零,直接返回空集合
return {};
} else {
// 调用 help 函数来寻找最佳的班次安排
Set<Shift> ans = help(shifts, {}, maxHours);
return ans;
}
}
这个代码的思想是使用递归回溯来解决问题,同时考虑了最大小时数限制和班次之间的重叠情况,以确保生成最大价值的班次组合。