题目描述
现在有n个工人的工作效率和最低薪资的信息。你需要从中招k个工人,你给这k个工人的薪资需要满足以下两点:
- 必须高于工人的最低薪资
- 工人之间的薪资比必须和他们的工作效率比一致
试求你招k个工人需要支付的最少薪资总数是多少?
示例
Input: quality = [10,20,5], wage = [70,50,30], k = 2 Output: 105.00000 Explanation: We pay 70 to 0th worker and 35 to 2nd worker.
题目分析
每个工人薪资的计算
首先假设我们已经选出来k个工人是谁,如何计算要给每个工人多少钱?
其实就是优先满足“性价比”最低的人,再根据“性价比”最低的人按比给其他工人定价。
拿示例举例,假设我们选定了第0个工人和第2个工人,我们可以算出两个工人的“性价比”(quality / wage)分别为:1/7和1/6,因此第0个工人的性价比最低,以他为基准给出价格。所以得到两个工人薪资分别为70和35。
所以对于这些工人,我们通过他们的“性价比”由低到高的顺序进行排序。按照这个顺序来选择工人的话总是可以先选到“性价比”最低的工人,也就是说我们可以先定好给价的基准。
怎样才能给工人的钱尽量少?
假设通过上述步骤我们已经确定了“性价比”最低的工人,那么剩下的工人应该怎么选择?其实就是从那些“性价比”更高的工人中选择工作效率低的工人,越低付的钱越少。注意是从“性价比”更高的工人中选择,因为一旦选了“性价比”更低的工人,我们的假设(确定了“性价比”最低的工人)就被破坏了。
思路总结
所以我们如果想找到最小花销,可以先按照工人的性价比由高到低排序,然后按照这个顺序选择工人。这样有一个好处:当前步骤加入选择名单的一定是性价比最低的工人。如果当前已经选了k个工人但是还需要将新的工人加入到选择名单中,那么就从已选的k个里面剔除工作效率最高的工人,然后把新的人选加入到选择名单中。注意每次选择了k个工人的时候都计算一下总价,记录最少的总价即为题目的解。
代码实现
class Solution {
public:
static bool cmp(pair<double, int>& a, pair<double, int>& b){
return a.first > b.first;
}
struct cmp_quality{
bool operator()(int& a, int& b){
return a < b;
}
};
double mincostToHireWorkers(vector<int>& quality, vector<int>& wage, int k) {
// 性价比序列,first是性价比数值,second是在原数组中的索引值
vector<pair<double, int>> q_w;
for(int i = 0; i < quality.size(); i++){
// 计算性价比
double cost_performance = double(quality[i]) / double(wage[i]);
pair<double, int> cur_performance(cost_performance, i);
q_w.push_back(cur_performance);
}
// 对性价比序列进行排序
sort(q_w.begin(), q_w.end(), cmp);
// 按照性价比顺序选择工人
// 建立一个最大堆,只记录quality,因为wage可以根据quality和性价比算出来
priority_queue<int, vector<int>, cmp_quality> cur_select;
// 记录当前的性价比
double cur_cp = 0;
// 记录当前选择的工人的quality总和
int cur_quality_sum = 0;
// 最小花销
double mincost = DBL_MAX;
for(int i = 0; i < q_w.size(); i++){
// 插入最新值
pair<double, int> cur_worker = q_w[i];
int index = cur_worker.second;
cur_select.push(quality[index]);
// quality总和更新
cur_quality_sum += quality[index];
// 性价比更新
cur_cp = cur_worker.first;
// 如果选了k个工人,计算总价更新然后剔除quality最高的
if(cur_select.size() == k){
// 如果总价比记录的小,就更新
if(mincost > double(cur_quality_sum) / cur_cp)
mincost = double(cur_quality_sum) / cur_cp;
// 删除quality最高的
cur_quality_sum -= cur_select.top();
cur_select.pop();
}
}
return mincost;
}
};