857. Minimum Cost to Hire K Workers

There are N workers.  The i-th worker has a quality[i] and a minimum wage expectation wage[i].

Now we want to hire exactly K workers to form a paid group.  When hiring a group of K workers, we must pay them according to the following rules:

Every worker in the paid group should be paid in the ratio of their quality compared to other workers in the paid group.
Every worker in the paid group must be paid at least their minimum wage expectation.
Return the least amount of money needed to form a paid group satisfying the above conditions.

 

Example 1:

Input: quality = [10,20,5], wage = [70,50,30], K = 2
Output: 105.00000
Explanation: We pay 70 to 0-th worker and 35 to 2-th worker.
Example 2:

Input: quality = [3,1,10,10,1], wage = [4,8,2,2,7], K = 3
Output: 30.66667
Explanation: We pay 4 to 0-th worker, 13.33333 to 2-th and 3-th workers seperately. 
 



https://blog.csdn.net/ihsin/article/details/82771186


https://leetcode.com/problems/minimum-cost-to-hire-k-workers/discuss/141768/Detailed-explanation-O(NlogN)

https://leetcode.com/problems/minimum-cost-to-hire-k-workers/solution/

版权声明:本文为博主原创文章,未经博主允许不得转载。    https://blog.csdn.net/yixin94/article/details/82771186
题意: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.


--------------------- 
作者:I-Hsin 
来源:CSDN 
原文:https://blog.csdn.net/ihsin/article/details/82771186 
版权声明:本文为博主原创文章,转载请附上博文链接!








上面的过程中,我们在尝试构建的时候, 会遇到一些不满足minium expectation的情况, 那些情况其实可以不用走。那我们再来看一下这个题目,寻找别的突破口。因为一个pay group只能有一个ratio, 那么我们就是对每个ratio找最小的k个人。我们可以对ratio先进行排序。从最小的ratio 开始,计算整个组的工资。我们可以用一个data structure去维持k 个candidates 的quality。 有了quality和ratio, 我们可以计算整一个组的工资。
公式: ratio * total quality = total wage for this group
我们用一个max priority queue来放置worker的quality。
Input: quality = [3,1,10,10,1], wage = [4,8,2,2,7], K = 3
ratio: [4/3, 8/1, 2/10, 2/10, 7/1]
sorted ratio [2/10, 2/10, 4/3, 7/1, 8/1]
quality :     [10, 10, 3, 1, 1]
maxHeap:  10, 3, 1
qualitySum: 10, 20, 23, 
res = 23 * 4/3 = 30.66667
Time: O(nlogn + nlogk) 
Space: O(n)
代码:


Approach 2: Heap
Intuition
As in Approach #1, at least one worker is paid their minimum wage expectation.
Additionally, every worker has some minimum ratio of dollars to quality that they demand. For example, if wage[0] = 100 and quality[0] = 20, then the ratio for worker 0 is 5.0.
The key insight is to iterate over the ratio. Let's say we hire workers with a ratio R or lower. Then, we would want to know the K workers with the lowest quality, and the sum of that quality. We can use a heap to maintain these variables.
Algorithm
Maintain a max heap of quality. (We're using a minheap, with negative values.) We'll also maintain sumq, the sum of this heap.
For each worker in order of ratio, we know all currently considered workers have lower ratio. (This worker will be the 'captain', as described in Approach #1.) We calculate the candidate answer as this ratio times the sum of the smallest K workers in quality.



不懂这个worker class 

class Solution {
    

    
    class Worker implements Comparable<Worker>{
        public int quality;
        public int wage;
        public Worker(int q, int w){
            quality = q;
            wage = w;
        }
        
        public double ratio(){
            return (double) wage / quality;
        }
        
        public int compareTo(Worker other){
            return Double.compare(ratio(), other.ratio());
        }
    }
        
    
    public double mincostToHireWorkers(int[] quality, int[] wage, int K) {
        int n = quality.length;
        Worker[] workers = new Worker[n];
        for(int i = 0; i < n; i++){
            workers[i] = new Worker(quality[i], wage[i]);
        }
        Arrays.sort(workers);
        double res = 1e9; // compare to an double , must use double , instead of an int
        // Integer res = Integer.MAX_VALUE;
        int totalQuality = 0;
        PriorityQueue<Integer> pq = new PriorityQueue<>((x, y) -> y - x);

        for(Worker w : workers){
            pq.offer(w.quality);
            totalQuality += w.quality;
            if(pq.size() > K){
                totalQuality -= pq.poll();
            }
            if(pq.size() == K){
                res = Math.min(res, totalQuality * w.ratio());
            }
        }
        return res;
    }
}


This solution is smart. However, it takes a while for me to understand it. Your code may need induction to prove its correctness during an interview. For example, given a list of workers sorted ascending by w/q ratio, we need to prove that for each worker at position >= K (assuming that position starts from 1), the sum of the K-1 qualities in the priority queue excluding the current worker itself is minimum so that the best cost we can get for this ratio is found. For the worker at position K, it's obviously true since you can only pick the K-1 works before it. Assuming that for the worker at position N > K it's true, for the worker at position N+1, we can also make it true by doing the following: if the quality at position N is larger than the priority queue peek, do nothing, otherwise the existing peek in the priority queue will be dropped and the quality at position N will be added.

Based on the above analysis, I wrote the following code, which is easier for me to understand. This code will also remove unnecessary offer into the max heap.

    

 

posted on 2018-11-08 17:00  猪猪&#128055;  阅读(199)  评论(0)    收藏  举报

导航