leetcode每日一题【雇佣 K 名工人的最低成本】2022/09/11

一、857. 雇佣 K 名工人的最低成本【难】

1、题目:

有 n 名工人。 给定两个数组 quality 和 wage ,其中,quality[i] 表示第 i 名工人的工作质量,其最低期望工资为 wage[i] 。

现在我们想雇佣 k 名工人组成一个工资组。在雇佣 一组 k 名工人时,我们必须按照下述规则向他们支付工资:

对工资组中的每名工人,应当按其工作质量与同组其他工人的工作质量的比例来支付工资。
工资组中的每名工人至少应当得到他们的最低期望工资。
给定整数 k ,返回 组成满足上述条件的付费群体所需的最小金额 。在实际答案的 10^-5 以内的答案将被接受。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/minimum-cost-to-hire-k-workers

思考过程:
1、首先想到性价比,但题目要求最小金额,性价比最高的时候未必是最小金额。
2、要点:quality只是支付的比例,其实只要找到在这个支付比例下,雇佣k个人所需最少的钱。

2、思路一:贪心+优先队列(堆)

思路过程:

  1. 选择了其中k个人,至少会有一个人获得的工资恰为其期望工资,而其他人的工资高于期望工资(关键逻辑);
  2. 单位工作质量期望的工资为:
    Q ( i ) = w a g e [ i ] q u a l i t y [ i ] Q(i)=\frac{wage[i]}{quality[i]} Q(i)=quality[i]wage[i]
    在k个人中,总工作质量为sum_quality。 任选一个工人i,那么任意选取k-1个其他工人满足Q(i)>Q(others),这k-1个工人的工资都能够被满足(和第一条对应)。那么总工资为:
    m a x _ w a g e > = w a g e [ i ] q u a l i t y [ i ] ∗ s u m _ q u a l i t y max\_wage >= \frac{wage[i]}{quality[i]} * sum\_quality max_wage>=quality[i]wage[i]sum_quality
  3. 若想总工资max_wage最少,那么就Q(i)递增找到选好k-1个工人,然后从第k个工人开始枚举,其的加入是否会有最小总工资。这k-1个工人不是固定的,因为当k+1个进入后,可能因为其quality比较少,使得sum_quality更少,

官解解释得非常好:
在这里插入图片描述

代码:

// 用到了优先队列和记录位置的数组s:O(n) 
// 排序和进出优先队列,t:O(nlogn)
class Solution {
public:
    double mincostToHireWorkers(vector<int>& quality, vector<int>& wage, int k) {
        // 对wage[i]/quality[i]的对应位置排序
        vector<int> pos(quality.size(),0);
        iota(pos.begin(),pos.end(),0); //递增赋值 
        sort(pos.begin(),pos.end(),[&](int &a, int &b){
            return wage[a]*quality[b] < wage[b]*quality[a];
        });
        
        double sum_quality = 0;
        //优先队列(最小堆)存放工作质量前k-1小的pos
        priority_queue<int, vector<int>, less<int>> q;
        for(int i=0; i<k-1; i++){
            sum_quality += quality[pos[i]];  //前k-1个工人的总工作质量
            q.push(quality[pos[i]]);
        }
        double result = DBL_MAX;
        // 贪心,每一步找到更小的工作质量进入优先队列,计算Q[i]更大时,是否是最小min_wage。
        for(int i= k-1 ;i<quality.size();i++){
            sum_quality += (double)quality[pos[i]];
            q.push(quality[pos[i]]);
            result = min(result,sum_quality*((double)wage[pos[i]]/quality[pos[i]]));
            sum_quality -= q.top();
            q.pop();
        }
        return result;
    }
};

代码中的新技能:

1、 iota()函数递增赋值
2、优先队列priority_queue<int, vector, less> q;
3、sort 中自定义的函数[&](int &a, int &b){
return wage[a]*quality[b] < wage[b]*quality[a];
});

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值