【BIT2021程设】13.任务安排——重载操作符排序、经典贪心

写在前面:

本系列博客仅作为本人十一假期过于无聊的产物,对小学期的程序设计作业进行一个总结式的回顾,如果将来有BIT的学弟学妹们在百度搜思路时翻到了这一条博客,也希望它能对你产生一点帮助(当然,依经验来看,每年的题目也会有些许的不同,所以不能保证每一题都覆盖到,还请见谅)。

不过本人由于学艺不精,代码定有许多不足之处,欢迎各位一同来探讨。

同时请未来浏览这条博客的学弟学妹们注意,对于我给出完整代码的这些题,仅作帮助大家理解思路所用(当然,因为懒,所以大部分题我都只给一个伪代码)。Anyway,请勿直接复制黏贴代码,小学期的作业也是要查重的,一旦被查到代码重复会严厉扣分,最好的方法是浏览一遍代码并且掌握相关的要领后自己手打一遍,同时也要做好总结和回顾的工作,这样才能高效地提升自己的代码水平。

加油!


成绩10开启时间2021年08月31日 星期二 12:30
折扣0.8折扣时间2021年09月5日 星期日 23:00
允许迟交关闭时间2021年10月10日 星期日 23:00

Description

小张经常为了事情太多安排不开而苦恼。现在他手头有n项任务,每项任务都有一个开始时间s_i结束时间e_i。要想完成一个任务必须从开始时间做到结束时间,并且同一时间小张只能进行一项任务。
小张想知道他最多可以完成几项任务。

Input

第一行一个整数n(1 \leq n \leq 300000 ),表示小张手头任务的个数。

接下来n行,每行两个整数s_i,e_i(1 \leq s_i < e_i \leq 10^9 ),表示任务的开始时间和结束时间。

Output

一行一个整数,表示小张最多可以完成几项任务。

测试用例 1以文本方式显示
  1. 4↵
  2. 1 5↵
  3. 5 10↵
  4. 7 13↵
  5. 12 18↵
以文本方式显示
  1. 3↵
1秒64M

题意分析:

        非常经典的一道贪心了可以说。

        还记得我们之前说的怎么证明贪心策略吗?就是“与其……不如”这个句式。那么怎么把这个句式套到这道题上呢?不急,我们先考虑两个任务的情况:

        两个任务实际上就两种情况,要么某一个任务的时间区间完全被包含在另一个里面,要么两者中间有一段重叠部分,前后各有一段独立部分,如下图所示:

         对于情况一,非常好取舍,我们毫无疑问选择蓝色的区间,因为他不仅开始的晚——可以给上一个任务留充足的时间,而且结束的早——可以给下一个任务留足够的时间。难点就在于情况二要怎么做取舍。我们这时候再多考虑一个结束时间更晚的任务(如果第三个任务并非结束更晚呢?那我们也可以重新对三个任务排序,并没有什么差别,读者可以自行思考一下):

             

        对于以上三种情况,第一种是无论选了红还是选了蓝都不能继续选绿;第二种是选了红才可以继续选绿,选了蓝则不行;第三种则是都可以。于是我们可以得出一个结论,选红总是不会比选蓝更差,换句话说,就是“与其选开始晚结束晚的,不如选开始早结束早的”。

        那么对于任意多的任务序列,类似的情况读者可以自己证明一下,我在此就不展开了。有了以上两部分贪心,我们归纳得到的贪心策略即为:对所有任务按结束时间从小到大排序,第一个任务必选,之后沿着这个序列遍历,能选谁就选谁,再画个更复杂的情况给读者呈现一下:

        上图是我们已经按照结束时间排好序的情况,我再用这张图解释一下我们的贪心策略:首先,红色必选,因为我们不选红色的理由只有两个——要么要选蓝色、要么要选绿色,然而这两个的结束时间都比红色晚,为了选它们而不选红色,是得不偿失;红色选取过后,蓝、绿已经被排除,按照我们的策略应该选择青色,这一步显而易见——因为青色被完全包含在黑色的区间内,怎么想青色都是更优的;选完青色过后我们淘汰了黑色,下一步根据我们的策略就选取了黄色——当然,此处选择黄、紫、浅蓝三种颜色对于结果不会有影响,但是如果在后面再加上一个任务,三者的情况又会如何呢?留给读者自己思考。


 伪代码:

        搞明白我们的贪心策略,这一题的思路就非常非常简单了。

        读入数据;//这里可以学会用pair二元组来保存二元变量

        按照任务的“结束时间”从小到大排序;//这里可以学会重载操作符,使得sort函数能够对二元组的第二个变元排序

        初始化一个当前时间curTime = 第一个任务的开始时间,初始化一个变量ans = 0保存输出;

        按照排序后的序列,从前之后依次选择,如果某任务的开始时间\geqcurTime, ans += 1,更新 curTime

        遍历结束后,输出ans


贴代码:

    #include <bits/stdc++.h>

    using namespace std;  
    typedef long long ll;  
    const int INF = 0x3f3f3f;  
    const int INT_MAX = 2147483646;  
      
    struct cmp{  //重载了“<”操作符,给sort函数使用
        bool operator()(pair<int,int> a, pair<int,int> b){  
            if(a.second < b.second)  
                return true;  
            else  
                return false;  
        }  
    };  
      
    int main(){  
        //ifstream infile("input.txt", ios::in);  
        //ofstream outfile("output.txt", ios::out);  
      
        vector<pair<int, int>> vec;  //一个保存二元组的容器
        int n;  
        cin >> n;  
        int tmp1, tmp2;  
        for(int i = 0; i < n; i++){  
            cin >> tmp1 >> tmp2;  
            vec.push_back(pair<int,int>(tmp1,tmp2));  
        }  
        sort(vec.begin(), vec.end(), cmp());  
      
        /*for(int i = 0; i < vec.size(); i++){ 
            cout << vec[i].first << ' ' << vec[i].second << endl; 
        }*/  
      
        int curTime = vec[0].second;  
        int count = 1;  
      
        for(int i = 1; i < vec.size(); i++){  
            if(vec[i].first >= curTime){  
                curTime = vec[i].second;  
                count++;  
            }  
        }  
      
        cout << count <<endl;  
        return 0;  
    }  

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里之码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值