LeetCode/雇佣K名工人的最低成本

有 n 名工人, 给定两个数组 quality 和 wage ,其中
quality[i] 表示第 i 名工人的工作质量,其最低期望工资为 wage[i]
现在我们想雇佣 k 名工人组成一个工资组,满足一下条件

  1. 对工资组中的每名工人,应当按其工作质量与同组其他工人的工作质量的比例来支付工资。
  2. 工资组中的每名工人至少应当得到他们的最低期望工资

返回应支付的最少工资

1. 贪心算法 + 动态规划

对于应支付总工资的计算,要使得每个人的最低期望工资得到满足

\[\frac{wage[i]}{totalw} = \frac{quality[i]}{totalq} \]

\[totalw = totalq×\frac{wage[i]}{quality[i]} \]

总工资会由组内每个人改该值的最大值决定,以满足每个人的最低工资期望
\(实际上,对于某一组,totalq是相同的,所以该组总工资由\frac{wage[i]}{quality[i]}权重最大的决定,不需要再计算其他的工人\)
所以我们要计算的最小工资存在两个影响维度
一是组的总工作质量,一是组内最大的权重
我们按其中一个维度排序进行贪心选择,对另一个维度进行反悔更新

//首先按权重进行升序排列,这样就可以从左往右进行遍历挑选当前组最大权重值
class Solution {
public:
    double mincostToHireWorkers(vector<int>& quality, vector<int>& wage, int k) {
        int n = quality.size();
        vector<int> h(n, 0);//记录序号映射
        iota(h.begin(), h.end(), 0);//产生从0开始连续数值
        sort(h.begin(), h.end(), [&](int& a, int& b) {//按质量工资比重从小到大重排序列
            return quality[a] * wage[b] > quality[b] * wage[a];});
        double res = 1e9;
        double totalq = 0.0;
        priority_queue<int, vector<int>, less<int>> q;//降序优先队列,第一个元素为最大工作质量
        for (int i = 0; i < k - 1; i++) { //入堆的元素,只保留工作质量,其他参数没有作用,因为总工资只由最新的元素(权重最大)决定
            totalq += quality[h[i]];//计算总工作质量
            q.push(quality[h[i]]);//工作质量入队列,由小到大排
        }
        for (int i = k - 1; i < n; i++) {//从小到大选取权重
            int idx = h[i];
            totalq += quality[idx];//计算当前总工作量
            q.push(quality[idx]);//入优先队列,方便后续反悔
            double totalc = ((double) wage[idx] / quality[idx]) * totalq;//计算当前最小价格,实际上也就是得到了对应权重下的最优解,即以idx为结尾的最小工资,也是动态规划思想
            res = min(res, totalc);//记录更新结果
            totalq -= q.top();//更新前k-1个的总工作质量
            q.pop();//保持k-1个值
        }
        return res;
    }
};
posted @ 2022-09-11 00:53  失控D大白兔  阅读(41)  评论(0编辑  收藏  举报