题目描述
数轴上有 n 个闭区间 [a_i, b_i]。取尽量少的点,使得每个区间内都至少有一个点(同区间内含的点可以是同一个)。
输入
第一行1个整数N(N<=100) 第2~N+1行,每行两个整数a,b(a,b<=100) |
输出
一个整数,代表选点的数目 |
样例输入
2
1 5
4 6
样例输出
1
思路
综述
这道题用到两个知识:多关键字排序和贪心算法
对于多关键字排序:
关键字1:区间的第二个端点,按照从头到尾的升序排列
关键字2:区间的第一个端点,按照从头到尾的降序排列
贪心算法:
按照上述排序好的区间:优先选择第一个区间的最后一个点,然后对区间已经合法的去除,再从剩下的区间内,选择第一个区间的最后一个端点
证明:
顺着推:按照上述排序之后:
如下图:第一个点的选择既可以是b点,也可以是a到b之间的任意一个,从这里来看b点是最优的选择,因为选择b点可以拆除3个区间,
循环得出答案;
过程
Step1:输入
结构体 P
a,b是两个端点值
struct P {
int a, b;
bool operator < (const struct P& p)const {
if (b != p.b) return b > p.b;//第一个最小 降序
return a < p.a;//第一个最大 升序
}
};
qq是优先队列,里面元素是结构体P
for (i = 0; i < n; i++) {
cin >> x.a >> x.b;
qq.push(x);
}
Step2:选点
从堆第一个选出一个点;
对堆里面的可清除的点进行剔除;
while (!qq.empty()) {
int num = qq.top().b;
total++;
while (!qq.empty()) {
if (qq.top().a > num)break;
qq.pop();
}
}
总结
深入思考
下面是,没有利用多关键字排序的结果,对于评测机,可以过;
也就是排序的时候,没考虑第一个端点的情况,细细思考,在选点的过程中也是没有用到第一个点。只是在排序的时候,徒增复杂度。
如下图:框出的是
没有多关键字排序的时间但是,时间更慢了,具体原因机器本身性能波动。
代码
#include <iostream>
#include <queue>
using namespace std;
int total = 0;
struct P {
int a, b;
bool operator < (const struct P& p)const {
if (b != p.b) return b > p.b;//第一个最小 降序
return a < p.a;//第一个最大 升序
}
};
int main() {
priority_queue<P> qq;
struct P x;
int n, i, j;
cin >> n;
for (i = 0; i < n; i++) {
cin >> x.a >> x.b;
qq.push(x);
}
while (!qq.empty()) {
//选点
int num = qq.top().b;
total++;
//剔除
while (!qq.empty()) {
if (qq.top().a > num)break;
qq.pop();
}
}
cout << total << endl;
}