题意:N个worker中选K个,每个worker有quality和wage两个属性。雇佣K个worker需要保证每个人的报酬比例和quality比例相同,而且不得低于其wage。目标是付出的报酬最小。
先考虑一个简单的情况,假设K个worker已经选定,如何定价格呢?假设有两个worker x, y, wage[x]/quality[x]<wage[y]/quality[y],那么把y的报酬设定成wage[y],x的报酬一定大于wage[x]:payment to x=quality[x]*wage[y]/quality[y]>quality[x]*wage[x]/quality[x]=wage[x]。
因此,如果K个worker已经选定,只要把wage[i]/quality[i]最高的worker(作为pivot)的payment设定成wage[i],在根据ratio算出其他worker的payment即可。
对于每个pivot worker,我们需要找出K-1个wage/quality比其小的worker而且还要让总的payment最小。wage/quality比pivot worker小的worker,一定满足payment>=wage的contraint,且total payment=wage[pivot]/quality[pivot]*sum of quality of other workers,所以我们只要保证sum of quality最小即可。
现将worker按照wage/quality从小到大排序,枚举到第i个worker作为pivot时,0~i-1 worker都是满足constraint的worker,只要从中找出K-1个quality最小的即可。
方法一:将worker不断插入有序set中,对于每个pivot worker,pop出前K小的,复杂度是KlogN,感觉会TLE。
方法二:用priority queue维护top K-1小的集合。如果新枚举的pivot worker quality比queue里面的最大元素小,那么queue.top()一定不是前K小的,所以将queue.top()移除,加入pivot worker quality。同时用sum维护top K小的quality之和,在更新queue元素时也更新sum。复杂度是logK.
另外C++ priority queue默认是大顶堆,老是记混。。
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
#include<stack>
using namespace std;
//leetcode 857. Minimum Cost to Hire K Workers
int T;
int N;
int M;
int K;
vector<int>vec0;
vector<int>vec1;
class Solution {
public:
bool cmp(pair<double,int>& a,pair<double,int>& b)//sort by wage/quality
{
return a.first<b.first;
}
double mincostToHireWorkers(vector<int>& quality, vector<int>& wage, int K) {
double ans=0x3f3f3f3f;
vector<pair<double,int> >rate;
for(int i=0;i<quality.size();i++)
{
rate.push_back(make_pair(1.0*wage[i]/quality[i],i));
}
sort(rate.begin(),rate.end());//can not use self-defined cmp
for(int i=0;i<rate.size();i++)
{
cout<<rate[i].second<<" "<<rate[i].first<<endl;
}
priority_queue<int>que;//maintain top K-1 largest element (exclude the pivot)
while(!que.empty()) que.pop();
int sum=0;
for(int i=0;i<rate.size();i++)
{
cout<<i<<" "<<sum<<endl;
if(que.size()<K-1)
{
que.push(quality[rate[i].second]);
sum+=quality[rate[i].second];
}
else
{
cout<<"ans tmp "<<1.0*rate[i].first*(sum+quality[rate[i].second])<<" "<<rate[i].first<<" "<<(sum+quality[rate[i].second])<<endl;
ans=min(ans,1.0*rate[i].first*(sum+quality[rate[i].second]));
if(!que.empty()&&que.top()>quality[rate[i].second])
{
int tmp=que.top();
que.push(quality[rate[i].second]);
que.pop();
sum-=tmp;
sum+=quality[rate[i].second];
cout<<"remove "<<tmp<<" push "<<quality[rate[i].second]<<endl;
}
}
}
return ans;
}
};
int main()
{
// priority_queue<int,vector<int>,greater<int> >que; //top is min element
// que.push(1);
// que.push(2);
// que.push(3);
// cout<<que.top()<<endl;
freopen("input.txt","r",stdin);
cin>>T;
for(int ca=1;ca<=T;ca++)
{
cin>>N>>M>>K;
vec0.clear();
vec1.clear();
for(int i=0;i<N;i++)
{
int tmp;
cin>>tmp;
vec0.push_back(tmp);
}
for(int i=0;i<M;i++)
{
int tmp;
cin>>tmp;
vec1.push_back(tmp);
}
Solution sol;
cout<<"Case #"<<ca<<": "<<sol.mincostToHireWorkers(vec0,vec1,K)<<endl;;
}
return 0;
}
//4 4 2
//4 4 4 5
//13 12 13 12