华为OD机试(C卷+D卷)2024真题目录(Java & c++ & python)
题目描述
部门在进行需求开发时需要进行人力安排。
当前部门需要完成 N 个需求,需求用 requirements 表述,requirements[i] 表示第 i 个需求的工作量大小,单位:人月。
这部分需求需要在 M 个月内完成开发,进行人力安排后每个月人力时固定的。
目前要求每个月最多有2个需求开发,并且每个月需要完成的需求不能超过部门人力。
请帮助部门评估在满足需求开发进度的情况下,每个月需要的最小人力是多少?
输入描述
输入为 M 和 requirements,M 表示需求开发时间要求,requirements 表示每个需求工作量大小,N 为 requirements长度,
- 1 ≤ N/2 ≤ M ≤ N ≤ 10000
- 1 ≤ requirements[i] ≤ 10^9
输出描述
对于每一组测试数据,输出部门需要人力需求,行末无多余的空格
用例
输入
3
3 5 3 4
输出
6
说明
输入数据两行,
第一行输入数据3表示开发时间要求,
第二行输入数据表示需求工作量大小,
输出数据一行,表示部门人力需求。
当选择人力为6时,2个需求量为3的工作可以在1个月里完成,其他2个工作各需要1个月完成。可以在3个月内完成所有需求。
当选择人力为5时,4个工作各需要1个月完成,一共需要4个月才能完成所有需求。
因此6是部门最小的人力需求。
解题思路
考虑暴力解法是从小遍历到大,遇到最小符合的数值即退出,这种线性关系可以直接考虑二分法。
那么每辆自行车载重:
- left: 至少是 1st_max(requirements),这样才能保证最重的人可以单独骑一辆自行车
- right: 至多是 1st_max(requirements) + 2nd_max(requirements),这样最重的两个人可以骑在一辆自行车
那么如何校验mid是否能够符合?
- 一辆自行车最多两人,那么对于最重的人坐两人的情况,必须至少得能跟最轻的人坐一辆。
- 首先将requirements升序排序,定义两个指针L,R,初始化L = 0,R=requirements.length -1。
L指向的就是体重最轻的人,R指向的就是体重最重的人。
- 如果 requirement[L] + requirement[R] <= mid,则说明最轻的人和最重的人可以坐一辆自行车,然后L++,R–,用车数量 need++
- 如果 requirement[L] + requirement[R] > mid,则说明最重的人只能一个人坐一辆自行车,无法搭配其他人,然后仅 R-- ,用车数量 need++
直到L > R时,即所有人都坐上了自行车时停止,此时我们比较need和M,
- 如果need <= M,则说明 mid 限重可以满足M辆车带走所有人,此时mid就是一个本题的一个可能解,但不一定时最优解,我们应该继续尝试更小的限重,即 right = mid - 1
- 如果need > M,则说明 mid 限重无法满足M辆车带走所有人,因此我们需要更大的限重,即 left = mid + 1
C++、Java、Python代码如下:
C++参考代码
#include <bits/stdc++.h>
using namespace std;
int m;
vector<int> requirements;
bool check(long limit) {
int l = 0; // 指向体重最轻的人
int r = requirements.size() - 1; // 指向体重最重的人
int need = 0; // 需要的自行车数量
while (l <= r) {
// 如果最轻的人和最重的人可以共享一辆车,则 l++, r--,
// 否则最重的人只能单独坐一辆车,即仅 r--
if (requirements[l] + requirements[r] <= limit) {
l++;
}
r--;
need++; // 用掉一辆车
}
// 判断当前自行车数量是否足够
return m >= need;
}
long solution() {
sort(requirements.begin(), requirements.end());
int n = requirements.size();
// 如果只有一个人
if (n == 1) {
return requirements[0];
}
// 初始情况下,最小限重为最重的那个人的体重
long minWeight = requirements[n - 1];
// 最大限重为最重的两个人体重之和
long maxWeight = requirements[n - 2] + requirements[n - 1];
long ans = maxWeight;
// 二分查找最小可行限重
while (minWeight <= maxWeight) {
long midWeight = (minWeight + maxWeight) / 2;
if (check(midWeight)) {
// 如果当前限重能满足需求,则尝试更小的限重
ans = midWeight;
maxWeight = midWeight - 1;
} else {
// 当前限重不够,则尝试更大的限重
minWeight = midWeight + 1;
}
}
return ans;
}
int main() {
cin >> m;
int weight;
while (cin >> weight) {
requirements.push_back(weight);
}
cout << solution() << endl;
return 0;
}
Java参考代码
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int m = Integer.parseInt(sc.nextLine());
int[] weights = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
System.out.println(findMinimumLimit(m, weights));
}
public static long findMinimumLimit(int m, int[] weights) {
Arrays.sort(weights);
int n = weights.length;
// 特殊情况:如果只有一个人,直接返回他的体重
if (n == 1) {
return weights[0];
}
// 最低限重:至少是最重的人的体重
long minLimit = weights[n - 1];
// 最高限重:最重的和次重的两个人的体重和
long maxLimit = weights[n - 2] + weights[n - 1];
long optimalLimit = maxLimit;
// 二分查找最佳限重
while (minLimit <= maxLimit) {
long midLimit = (minLimit + maxLimit) >> 1; // 计算中间限重
if (canCarryAll(midLimit, m, weights)) {
optimalLimit = midLimit; // 找到一个可能的最优解
maxLimit = midLimit - 1; // 尝试更小的限重
} else {
minLimit = midLimit + 1; // 限重太小,尝试更大的限重
}
}
return optimalLimit;
}
/**
* @param limit 每辆自行车的限重
* @param m 可用自行车的数量
* @param weights 人的体重数组
* @return true 如果可以用 m 辆自行车带走所有人
*/
public static boolean canCarryAll(long limit, int m, int[] weights) {
int l = 0; // 最轻的人的索引
int r = weights.length - 1; // 最重的人的索引
int bikesNeeded = 0; // 需要的自行车数量
while (l <= r) {
// 如果最轻和最重的人可以共用一辆车
if (weights[l] + weights[r] <= limit) {
l++;
}
r--;
bikesNeeded++; // 使用一辆自行车
}
// 判断可用的自行车数量是否足够
return bikesNeeded <= m;
}
}
Python参考代码
# 输入获取
m = int(input())
requirements = list(map(int, input().split()))
def check(limit):
"""
:param limit: 每辆自行车的限重
:return: 如果给定每辆自行车的限重limit,能否用m辆车带走所有人
"""
l = 0 # 指向体重最轻的人
r = len(requirements) - 1 # 指向体重最重的人
need = 0 # 需要的自行车数量
while l <= r:
# 如果最轻的人和最重的人可以共用一辆车
if requirements[l] + requirements[r] <= limit:
l += 1
r -= 1
need += 1 # 用掉一辆车
# 如果当前有的自行车数量足够,则返回True
return need <= m
def getResult():
if len(requirements) == 1:
return requirements[0]
requirements.sort()
low = requirements[-1] # 每辆自行车的限重至少是最重的人的体重
high = requirements[-1] + requirements[-2] # 最多是最重的两个人体重之和
ans = high
# 二分查找
while low <= high:
mid = (low + high) // 2
if check(mid):
ans = mid # 可能是解,继续寻找更优解
high = mid - 1
else:
low = mid + 1
return ans
# 算法调用
print(getResult())