写在前面:
本系列博客仅作为本人十一假期过于无聊的产物,对小学期的程序设计作业进行一个总结式的回顾,如果将来有BIT的学弟学妹们在百度搜思路时翻到了这一条博客,也希望它能对你产生一点帮助(当然,依经验来看,每年的题目也会有些许的不同,所以不能保证每一题都覆盖到,还请见谅)。
不过本人由于学艺不精,代码定有许多不足之处,欢迎各位一同来探讨。
同时请未来浏览这条博客的学弟学妹们注意,对于我给出完整代码的这些题,仅作帮助大家理解思路所用(当然,因为懒,所以大部分题我都只给一个伪代码)。Anyway,请勿直接复制黏贴代码,小学期的作业也是要查重的,一旦被查到代码重复会严厉扣分,最好的方法是浏览一遍代码并且掌握相关的要领后自己手打一遍,同时也要做好总结和回顾的工作,这样才能高效地提升自己的代码水平。
加油!
成绩 | 10 | 开启时间 | 2021年08月31日 星期二 12:30 |
折扣 | 0.8 | 折扣时间 | 2021年09月5日 星期日 23:00 |
允许迟交 | 否 | 关闭时间 | 2021年10月10日 星期日 23:00 |
Description
小张经常为了事情太多安排不开而苦恼。现在他手头有项任务,每项任务都有一个开始时间
结束时间
。要想完成一个任务必须从开始时间做到结束时间,并且同一时间小张只能进行一项任务。
小张想知道他最多可以完成几项任务。
Input
第一行一个整数,表示小张手头任务的个数。
接下来n行,每行两个整数,表示任务的开始时间和结束时间。
Output
一行一个整数,表示小张最多可以完成几项任务。
测试用例 1 | 以文本方式显示
| 以文本方式显示
| 1秒 | 64M |
题意分析:
非常经典的一道贪心了可以说。
还记得我们之前说的怎么证明贪心策略吗?就是“与其……不如”这个句式。那么怎么把这个句式套到这道题上呢?不急,我们先考虑两个任务的情况:
两个任务实际上就两种情况,要么某一个任务的时间区间完全被包含在另一个里面,要么两者中间有一段重叠部分,前后各有一段独立部分,如下图所示:
对于情况一,非常好取舍,我们毫无疑问选择蓝色的区间,因为他不仅开始的晚——可以给上一个任务留充足的时间,而且结束的早——可以给下一个任务留足够的时间。难点就在于情况二要怎么做取舍。我们这时候再多考虑一个结束时间更晚的任务(如果第三个任务并非结束更晚呢?那我们也可以重新对三个任务排序,并没有什么差别,读者可以自行思考一下):
对于以上三种情况,第一种是无论选了红还是选了蓝都不能继续选绿;第二种是选了红才可以继续选绿,选了蓝则不行;第三种则是都可以。于是我们可以得出一个结论,选红总是不会比选蓝更差,换句话说,就是“与其选开始晚结束晚的,不如选开始早结束早的”。
那么对于任意多的任务序列,类似的情况读者可以自己证明一下,我在此就不展开了。有了以上两部分贪心,我们归纳得到的贪心策略即为:对所有任务按结束时间从小到大排序,第一个任务必选,之后沿着这个序列遍历,能选谁就选谁,再画个更复杂的情况给读者呈现一下:
上图是我们已经按照结束时间排好序的情况,我再用这张图解释一下我们的贪心策略:首先,红色必选,因为我们不选红色的理由只有两个——要么要选蓝色、要么要选绿色,然而这两个的结束时间都比红色晚,为了选它们而不选红色,是得不偿失;红色选取过后,蓝、绿已经被排除,按照我们的策略应该选择青色,这一步显而易见——因为青色被完全包含在黑色的区间内,怎么想青色都是更优的;选完青色过后我们淘汰了黑色,下一步根据我们的策略就选取了黄色——当然,此处选择黄、紫、浅蓝三种颜色对于结果不会有影响,但是如果在后面再加上一个任务,三者的情况又会如何呢?留给读者自己思考。
伪代码:
搞明白我们的贪心策略,这一题的思路就非常非常简单了。
读入数据;//这里可以学会用pair二元组来保存二元变量
按照任务的“结束时间”从小到大排序;//这里可以学会重载操作符,使得sort函数能够对二元组的第二个变元排序
初始化一个当前时间 = 第一个任务的开始时间,初始化一个变量
= 0保存输出;
按照排序后的序列,从前之后依次选择,如果某任务的开始时间,
+= 1,更新
;
遍历结束后,输出;
贴代码:
#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;
}