一、题目
题目描述
项目组共有N个开发人员,项目经理接到了M个独立的需求,每个需求的工作量不同,且每个需求只能由一个开发人员独立完成,不能多人合作。假定各个需求直接无任何先后依赖关系,请设计算法Q帮助项目经理进行工作安排,使整个项目能用最少的时间交付
输入输出
输入
第一行输入为M个需求的工作量,单位为天,用逗号隔开。
例如:X1,X2,X3…Xm
表示共有M个需求,每个需求的工作量分别为X1天,X2天…Xm天。其中0<M<30; 0<Xm<200
第二行输入为项目组人员数量N,例如:表示共有5名员工,其中0<N<10
输出
最快完成所有工作的天数
样例1
输入
6 2 7 7 9 3 2 1 3 11 4
2
输出
28
说明:
共有两位员工,其中一位分配需求6 2 7 7 3 2 1共需要28天完成,另一位分配需求9 3 11 4共需要27天完成,故完成所有工作至少需要28天。
样例2
输入
3 6 9 12 15 18 21 24 27 30
6
输出
30
一、代码与思路
🧠C++语言思路
1.首先,将需求的工作量按照从大到小排序,以平衡员工的负载。
2.创建一个长度为N的数组employee hours,用于记录每个员工已分配的工作量。
3.初始化一个变量min time为INT MAX,用于记录最短完成时间。
4.使用回溯法尝试所有的分配方案:
- 定义一个回溯函数backtrack,参数为当前需求的索引i。
- 如果所有任务已分配完毕,更新最短完成时间为employee hours数组中的最大值,然后返回。
- 遍历所有员工,尝试将当前需求分配给每个员工:
- 如果当前分配方案已经超过最短时间,跳过。
- 将当前需求的工作量加到该员工的工作量中。
- 递归调用backtrack函数,继续分配下一个需求。
- 将当前需求的工作量从该员工的工作量中减去(回溯)
5.调用回溯函数backtrack(0)开始尝试所有分配方案。
6.返回最短完成时间min time作为结果。
✅C++代码
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using std::cin;
using std::cout;
using std::string;
using std::vector:
/**
* 验证是否可以将任务分配给N个人,使得每个人的时间不超过T
* @param workloads 任务列表(需降序列表)
* @param n 人数
* @param T 候选时间
* @return 是否可行
*/
bool idPossible(vector<int> workloads, int n, int T)
{
// 降序排序,优先处理最大任务
sort(workloads.begin(), workloads.end(), std::greater<int>());
vector<int> workers(n, 0); // 记录每个员工当前的总工作量
// 遍历每个任务
for (int w : workloads)
{
// 找到当前工作量最小的员工
int min_idx = 0;
int min_time = workers[0]; // 记录最小工作量的员工id和工作量
// 遍历每个员工
for (int i = 0; i < n; ++i)
{
// 若该员工当前工作量小于当前任务,则更新最小工作量
if (workers[i] < min_time)
{
min_time = workers[i]; // 更新最小工作量
min_idx = i; // 更新最小工作量的员工id
}
}
// 若无法分配给任何人,则候选时间不可行
if (min_time + w > T)
{
return false;
}
workes[min_idx] += w; // 分配给最小工作量的员工
}
return true; // 所有任务均分配给员工且每个员工的工作量不超过候选时间
}
int main(void)
{
// 读取输入的任务列表
string line;
std::getline(cin, line);
// 处理逗号变为空格
for(char &c : line)
{
if (c == ',')
{
c = ' ';
}
}
vector<int> workloads; // 存储的任务列表
stringstream ss(line);
int num;
while (ss >> num)
{
workloads.push_back(num);
}
// 读取员工的数量
int num_works = 0;
cin >> num_works;
// 启用二分查找
int left = std::*max_element(workloads.begin(), workloads.end()); // left为最大的单个任务的时间
int right = std::accumulate(workloads.begin(), workloads.end(), 0); // right为所以任务时间的总和
// 二分查找查找最小时间的可行性
while (left < right)
{
int mid = (left + right) / 2; // 取中间值
if (isPossible(workloads, num_works, mid)
{
right = mid; // 当前时间可行缩小右边界
}
else
{
left = mid + 1; // 当前时间不可行,扩大左边界
}
}
// 输出结果
cout << left << "\n";
return 0;
}