1029. Two City Scheduling

1029. 两地调度

公司计划面试 2N 人。第 i 人飞往 A 市的费用为 costs[i][0],飞往 B 市的费用为 costs[i][1]

返回将每个人都飞到某座城市的最低费用,要求每个城市都有 N 人抵达

 

示例:

输入:[[10,20],[30,200],[400,50],[30,20]]
输出:110
解释:
第一个人去 A 市,费用为 10。
第二个人去 A 市,费用为 30。
第三个人去 B 市,费用为 50。
第四个人去 B 市,费用为 20。

最低总费用为 10 + 30 + 50 + 20 = 110,每个城市都有一半的人在面试。

 

提示:

  1. 1 <= costs.length <= 100
  2. costs.length 为偶数
  3. 1 <= costs[i][0], costs[i][1] <= 1000

解法一

//时间复杂度O(n), 空间复杂度O(n)
class Solution {
public:
    int twoCitySchedCost(vector<vector<int>>& costs) {
        priority_queue<int, vector<int>, greater<int>> negative, positive;//小顶堆
        int total_cost = 0, zero_count = 0;
        for(auto vec : costs) {
            total_cost += min(vec[0], vec[1]);
            
            int diff = vec[0] - vec[1];
            if(diff > 0) positive.push(diff);
            else if(diff < 0) negative.push(-diff);
            else zero_count++;
        }
        
        auto& shorter = negative.size() > positive.size() ? positive : negative;
        auto& longer = negative.size() > positive.size() ? negative : positive;
        
        int n = (longer.size() - shorter.size() - zero_count) / 2;
        while(n--) {
            total_cost += longer.top();
            longer.pop();
        }
        return total_cost;
    }
};

思路:

不考虑两地人数相等的情况下,先考虑最低费用total_cost,它等于costs中每一对元素 { vec[0], vec[1] }较小者之和。

对于元素对 { vec[0], vec[1] },两地费用差diff = vec[0] - vec[1]。如果diff > 0,暂且称为正对,此时去B地划算;如果diff < 0,暂且称为负对,选A地划算。如果diff = 0,暂且称为零对,去两地费用一样。

解法一使用了两个堆:positive记录正对的费用差,negative记录了负对的费用差(的绝对值)。使用一个计数zero_count记录零对的个数。

最低费用的条件:两个堆的元素数量之差(设差为正)小于zero_count。(因为零对可以充当正对,也可当负对)。

如果不满足最低费用条件,需要对元素数量大的堆的最小元素(小顶堆的堆顶)进行翻转(如正对{10, 20}本来应选A地,费用为10;翻转后选B地,相比最低费用的额外的费用为abs(diff) = 10,也就是20)。每翻转一次,两个堆的元素数量分别会加1、减1,并且要将额外费用加到最低费用total_cost上。反复翻转堆顶元素,直到满足最低费用条件,返回total_cost。

代码如上。

2019/09/08 00:54
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值