LeetCode 857. Minimum Cost to Hire K Workers
題意: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