leetcode2532. 过桥的时间 题解

原题:https://leetcode.cn/problems/time-to-cross-a-bridge/description/

class Solution {
    typedef pair<int, int> PII;
public:
    int findCrossingTime(int n, int k, vector<vector<int>>& time) {
        /**
        四个堆结构
        wait_l: 效率低优先(下标大), 维护工人下标(可表示效率)和到达桥的时间
        work_l: 完成时间小优先,维护完成时间和工人下标

        如果桥上有人在过桥,其他工人不能过桥要等待,curTime+=过桥所需时间后即可过桥
        **/

        //下标越大,效率越低
        stable_sort(time.begin(), time.end(), [&](auto &va, auto &vb){
            return va[0] + va[2] < vb[0] + vb[2];
        });
        priority_queue<PII> wait_l,  wait_r;
        priority_queue<PII, vector<PII>, greater<PII> > work_l, work_r;
        for(int i = k - 1; i >= 0; i--)
            wait_l.push({i, 0});
        
        int curTime = 0;
        while(n){
            if(wait_r.size()){
                auto [i, t] = wait_r.top();
                wait_r.pop();
                curTime += time[i][2];
                work_l.push({curTime + time[i][3], i});
                // cout << "r->l: " << i << " curTime: " << curTime << endl;
            }else if(wait_l.size()){
                auto [i, t] = wait_l.top();
                wait_l.pop();
                curTime += time[i][0];
                // cout << "l->r: " << i << " curTime: " << curTime << endl;
                work_r.push({curTime + time[i][1], i});
                n--;//只要从左边过去右边一个人,n就要--了。以免左边多过桥的人拖慢总时间
            }//一次过一个人
            //如果工人搬东西的时间太长,一直在work,而等待过桥的人已经没了,curTime将会卡住
            //需要将curTime更新到最快一个工人work完到wait到时间
            else if (work_l.empty()) curTime = work_r.top().first;
            else if (work_r.empty()) curTime = work_l.top().first;
            else curTime = min(work_l.top().first, work_r.top().first);
            // cout << "work_r.size(): " << work_r.size() << endl;
            // cout << "work_r.top().first: " << work_r.top().first << endl;
            // cout << "curTime: " << curTime << endl;
            while(work_r.size() && work_r.top().first <= curTime){
                auto [t, i] = work_r.top();
                work_r.pop();
                wait_r.push({i, t});
                // cout << "old: " << i << " curTime: " << curTime << endl;
            }
            while(work_l.size() && work_l.top().first <= curTime){
                auto [t, i] = work_l.top();
                work_l.pop();
                wait_l.push({i, t});
                // cout << "new: " << i << " curTime: " << curTime << endl;
            }
            
        }
        //最后箱子已经搬完,还剩下一批右边的人,最后一个过桥人的时间即为答案(最后不用考虑过桥顺序,答案相同)
        //此时curTime可能 < t
        while(wait_r.size()){
            auto [i, t] = wait_r.top();
            wait_r.pop();
            curTime += time[i][2];
        }
        while(work_r.size()){
            auto [t, i] = work_r.top();
            work_r.pop();
            curTime = max(t, curTime) + time[i][2];
        }
        return curTime;
    }
};

 

更好的写法是改变while(n)中的顺序,过桥之后立刻判断n,右边的人全在work_r中,则最后可以不需要while(wait_r.size())的循环

class Solution {
    typedef pair<int, int> PII;
public:
    int findCrossingTime(int n, int k, vector<vector<int>>& time) {
        /**
        四个堆结构
        wait_l: 效率低优先(下标大), 维护工人下标(可表示效率)和到达桥的时间
        work_l: 完成时间小优先,维护完成时间和工人下标

        如果桥上有人在过桥,其他工人不能过桥要等待,curTime+=过桥所需时间后即可过桥
        **/

        //下标越大,效率越低
        stable_sort(time.begin(), time.end(), [&](auto &va, auto &vb){
            return va[0] + va[2] < vb[0] + vb[2];
        });
        priority_queue<PII> wait_l,  wait_r;
        priority_queue<PII, vector<PII>, greater<PII> > work_l, work_r;
        for(int i = k - 1; i >= 0; i--)
            wait_l.push({i, 0});
        
        int curTime = 0;
        while(n){
            
            while(work_r.size() && work_r.top().first <= curTime){
                auto [t, i] = work_r.top();
                work_r.pop();
                wait_r.push({i, t});
                // cout << "old: " << i << " curTime: " << curTime << endl;
            }
            while(work_l.size() && work_l.top().first <= curTime){
                auto [t, i] = work_l.top();
                work_l.pop();
                wait_l.push({i, t});
                // cout << "new: " << i << " curTime: " << curTime << endl;
            }
            
            if(wait_r.size()){
                auto [i, t] = wait_r.top();
                wait_r.pop();
                curTime += time[i][2];
                work_l.push({curTime + time[i][3], i});
                // cout << "r->l: " << i << " curTime: " << curTime << endl;
            }else if(wait_l.size()){
                auto [i, t] = wait_l.top();
                wait_l.pop();
                curTime += time[i][0];
                // cout << "l->r: " << i << " curTime: " << curTime << endl;
                work_r.push({curTime + time[i][1], i});
                n--;//只要从左边过去右边一个人,n就要--了。以免左边多过桥的人拖慢总时间
            }//一次过一个人
            //如果工人搬东西的时间太长,一直在work,而等待过桥的人已经没了,curTime将会卡住
            //需要将curTime更新到最快一个工人work完到wait到时间
            else if (work_l.empty()) curTime = work_r.top().first;
            else if (work_r.empty()) curTime = work_l.top().first;
            else curTime = min(work_l.top().first, work_r.top().first);
            // cout << "work_r.size(): " << work_r.size() << endl;
            // cout << "work_r.top().first: " << work_r.top().first << endl;
            // cout << "curTime: " << curTime << endl;
        }
        //最后箱子已经搬完,还剩下一批右边的人,最后一个过桥人的时间即为答案(最后不用考虑过桥顺序,答案相同)
        //此时curTime可能 < t
        // while(wait_r.size()){
        //     auto [i, t] = wait_r.top();
        //     wait_r.pop();
        //     curTime += time[i][2];
        // }
        while(work_r.size()){
            auto [t, i] = work_r.top();
            work_r.pop();
            curTime = max(t, curTime) + time[i][2];
        }
        return curTime;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值