857. 雇佣 K 名工人的最低成本 Hard

文章讲述了如何在给定工人质量和最低期望工资的情况下,找到雇佣k名工人组成的团队,确保每个工人的工资不低于最低期望且按照工作质量比例支付,求解最小总成本。作者提供了两种解决方案,一种是利用优先级队列优化算法,另一种是通过预处理工人数据并排序来实现。
摘要由CSDN通过智能技术生成

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

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

        1.对工资组中的每名工人,应当按其工作质量与同组其他工人的工作质量的比例来支付工资。

        2.工资组中的每名工人至少应当得到他们的最低期望工资。

给定整数 k ,返回 组成满足上述条件的付费群体所需的最小金额 。在实际答案的 10-5 以内的答案将被接受。

示例 1:

输入: quality = [10,20,5], wage = [70,50,30], k = 2
输出: 105.00000
解释: 我们向 0 号工人支付 70,向 2 号工人支付 35。

示例 2:

输入: quality = [3,1,10,10,1], wage = [4,8,2,2,7], k = 3
输出: 30.66667
解释: 我们向 0 号工人支付 4,向 2 号和 3 号分别支付 13.33333。

提示:

 ·n == quality.length == wage.length

 ·1 <= k <= n <= 104

 ·1 <= quality[i], wage[i] <= 104

题目大意:需找出k个工人,要求k个工人的工资都大于自身最低薪资,同时保证 给定工资:工作质量 相同。

分析:设选定的所有工人的给定工资:工作质量p

(1)由于k个工人的给定工资:工作质量相同,因此p由选择工人中最大的最低工资:工作质量决定;

(2)由(1)可得选择的所有人的最低工资:工作质量都小于等于p,因此当先确定p再选工人时,只能从最低工资:工作质量小于等于p的工人中选择;

(3)由于p相同,选择的所有工人中工作质量越高的工人,给定的工资越高;

(4)由(2)和(3)可得,当p确定时,只需从最低工资:工作质量小于等于p的工人中按工作质量由低到高选择k人即可确定最小金额;

(5)由于题中p不确定,因此只需枚举所有工人的最低工资:工作质量,每次枚举使用(4)中的方法计算最小金额m,最后保留最小的m即为最终的最小金额。

思路优化:设工人i的最低工资:工作质量p_i,确定第i个工人的p_ip时的最低工资为m_i

(1)依据最低工资:工作质量对工人升序排序,排序后问题转换为:当确定第i个工人的最低工资:工作质量p时,只需从前i-1个工人中寻找k-1个工作质量最低的工人即可;

(2)由于所选工人的p相同,因此最小金额=所选工人的工作质量之和*p;

(3)由(1)和(2)可得,对工人的最低工资:工作质量升序排序后,再进行遍历,同时遍历过程中用优先级队列维护前i-1个工人中最低的k-1个工作质量,并且用变量totalq维护最低的k-1个工作质量之和,则m_i=p_i*totalq

class Solution {
public:
    double mincostToHireWorkers(vector<int>& quality,vector<int>& wage,int k){
        double m=DBL_MAX;
        int N=quality.size();
        int totalq=0;
        priority_queue<int> q;//维护最低的k-1个工作质量
        vector<int> index(N);//辅助排序的索引数组
        iota(index.begin(),index.end(),0);//初始化索引数组
        //对最低工资:工作质量升序排序
        sort(index.begin(),index.end(),[&](int id1,int id2){
            return quality[id1]*wage[id2]>quality[id2]*wage[id1];
        });
        for(int i=0;i<k-1;++i){
            totalq+=quality[index[i]];
            q.push(quality[index[i]]);
        }
        for(int i=k-1;i<N;++i){
            int idx=index[i];
            totalq+=quality[idx];
            q.push(quality[idx]);
            m=min(m,wage[idx]*1.0/quality[idx]*totalq);//计算最低工资
            //维护最低的k-1个工作质量
            totalq-=q.top();
            q.pop();
        }
        return m;
    }
};
//优化前的代码
// class worker{
// public:
//     worker(int quality,double p):_quality(quality),_p(p){}
//     int _quality;
//     double _p;
// };
// bool operator<(const worker& w1,const worker& w2){
//     return w1._quality<w2._quality;
// }
// class Solution {
// public:
//     double findMinCost(vector<worker>& workers, int k,double p){
//         double ans=0;
//         int num=0;
//         for(int i=0;i<workers.size()&&num<k;++i){
//             if(workers[i]._p<=p){
//                 ++num;
//                 ans+=p*workers[i]._quality;
//             }
//         }
//         if(num==k) return ans;
//         return DBL_MAX;
//     }
//     double mincostToHireWorkers(vector<int>& quality,vector<int>& wage,int k){
//         double m=DBL_MAX;
//         int N=quality.size();
//         unordered_set<double> ps;
//         vector<worker> workers;
//         workers.reserve(N);
//         for(int i=0;i<N;++i){
//             double p=wage[i]*1.0/quality[i];
//             ps.insert(p);
//             workers.emplace_back(quality[i],p);
//         }
//         sort(workers.begin(),workers.end());
//         for(auto& ele:ps){
//             m=min(m,findMinCost(workers,k,ele));
//         }
//         return m;
//     }
// };

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值