【华为OD机试真题】423、项目排期 、最快完成所有工作的天数 | 机试真题+思路参考+代码解析(CD卷)(C++)

一、题目

题目描述

项目组共有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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值