题目链接
题目大意
比如有 3 个工人,我们要组成 2 个人的工资组,其工作质量数组为[10,20,5],最低期望工资数组为[70,50,30],那么可以证明选择 0 号工人支付70,2 号工人支付35为最优解。
解题思路
这里假定总花费为 totalc
,工资组工作质量总和为 totalq
,那么如果一个工人在工资组中,其应该满足如下条件:
可以转化为:
我们的目的是需要找到最小的 totalc
,那么可以进行贪心选择,我们将 wagei/qualityi 定义为性价比 pqratioi,pqratioi是确定的,那么如果我们现在确定一个工人 i,其作为工资组性价比上限,那么只需要寻找性价比小于等于上限的即可,且 totalq
越小越好,那么就寻找 k-1 个满足性价比要求的最小的工作质量的工人即可。
这样我们可以先用性价比对工人从小到大排序,然后从第k-1(从0开始编号)个工人开始,其性价比作为工资组的性价比工资上线,再从前面选出 k-1 个满足性价比条件的且工作质量最小的工人,这个可以使用大根堆维护。每次更新答案即可,答案最大可能到 1e8(1e4*1e4)
代码(C++)
class Solution {
public:
double mincostToHireWorkers(vector<int>& quality, vector<int>& wage, int k) {
int n = quality.size();
vector<int> idx(n);
iota(idx.begin(), idx.end(), 0); // [0,1,2,...,n-1]
sort(idx.begin(), idx.end(), [&](int& a, int& b) {
return quality[a] * wage[b] > quality[b] * wage[a];
});
double ans = 1e8;
double totalq = 0.0;
priority_queue<int, vector<int>, less<int>> q;
for (int i = 0; i < k - 1; i++) {
totalq += quality[idx[i]];
q.push(quality[idx[i]]);
}
for (int i = k - 1; i < n; i++) {
int id = idx[i];
totalq += quality[id];
q.push(quality[id]);
double totalc = ((double) wage[id] / quality[id]) * totalq;
ans = min(ans, totalc);
totalq -= q.top();
q.pop();
}
return ans;
}
};