华为OD-部门人力分配

题目描述
部门在进行需求开发时需要进行人力安排。

当前部门需要完成 N 个需求,需求用 requirements 表述,requirements[i] 表示第 i 个需求的工作量大小,单位:人月。

这部分需求需要在 M 个月内完成开发,进行人力安排后每个月人力时固定的。

目前要求每个月最多有2个需求开发,并且每个月需要完成的需求不能超过部门人力。

请帮助部门评估在满足需求开发进度的情况下,每个月需要的最小人力是多少?

输入描述
输入为 M 和 requirements,M 表示需求开发时间要求,requirements 表示每个需求工作量大小,N 为 requirements长度,

1 ≤ N/2 ≤ M ≤ N ≤ 10000
1 ≤ requirements[i] ≤ 10^9
输出描述
对于每一组测试数据,输出部门需要人力需求,行末无多余的空格
用例
在这里插入图片描述
题目解析
本题是将二分和双指针考点结合在了一起。

本题我们可以换个说法:

目前有 N 个人(N个需求),

每个人的体重为requirements[i],(每个需求开发需要的人力为requirements[i])

以及 M 辆自行车(M个月开发),

每辆自行车至多坐两人(每个月至多开发两个需求),

现在想要用 M 辆自行车带走 N 个人,问每辆自行车的限重至少是多少?(M个月开发完N个需求,每个月至少需要多少人力)

每辆自行车载重:

1.min 至少是 1st_max(requirements),这样才能保证最重的人可以单独骑一辆自行车
2.max 至多是 1st_max(requirements) + 2nd_max(requirements),这样最重的两个人可以骑在一辆自行车商
我们可以在该[min, max]范围内二分找中间值mid,作为每辆自行车的限重去尝试(check),看对应限重下至少需要多少辆自行车。

比如二分取中间值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就是一个本题的一个可能解,但不一定时最优解,我们应该继续尝试更小的限重,即max = mid - 1
如果need > M,则说明 mid 限重无法满足M辆车带走所有人,因此我们需要更大的限重,即 min = mid + 1
然后继续二分取中间值作为限重带入前面双指针逻辑check。

另外本题需要注意整型溢出问题。
JS算法源码

const rl = require("readline").createInterface({
    input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

// 输入处理
void (async function () {
   
  const m = parseInt(await readline());
  const requirements = (await readline()).split(" ").map(Number);

  console.log(getResult(m, requirements));
})();

function getResult(m, requirements) {
   
  requirements.sort((a, b) => a - b);

  const n = requirements.length;

  // 每辆自行车的限重 至少是 最重的那个人的体重
  let min = requirements[n - 1];
  // 每辆自行车的限重 至多是 最重的和次重的那两个的体重
  let max = requirements[n - 2] + requirements[n - 1];

  let ans = max;

  // 二分取中间值
  while (min <= max) {
   
    const mid = Math.floor(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风吹沙丘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值