1. 程式人生 > >LeetCode 857. Minimum Cost to Hire K Workers

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