点击查看代码
/*
给出N个闭区间[x,y],求最少需要确定多少个点,才能使每个闭区间中都至少存在一个点。例如对闭区间[1,4],[2,6],[5,7]来说,需要两个点1和5才能保证每个闭区间内都至少有一个点
输入样例:
3 1 4 2 6 5 7
//有3个闭区间:[1,4] [2,6] [5,7]
输出样例:
5 1
//需要确定两个点5和1才能保证每个闭区间内都至少有一个点
解题思路:
1、区间选点问题和区间不相交问题的策略是一样的。如果I1区间在I2区间内,此时在I1中取点可以保证这个点也会在I2内(在范围较小的区间内取点)
2、对所有区间排序,左端点从大到小排序,左端点相同时,右端点小的在前(即区间范围小的排在前,在后续选择过程中优先被选择),
为了使每个闭区间内都存在一个点,此时只需要取每个区间的左端点即可,这样就可以使这个点覆盖到尽可能多的区间
3、区间选点代码只需要将区间不相交代码中的“I[i].y <= lastX”改为“I[i].y < lastX”即可,lastX记录上一个选择区间的左端点(初始化为区间左端点x最大的那个点),
遍历剩余的闭区间,如果待选区间右端点小于lastX,则两个区间范围不相交,待选区间符合要求,这样选择的点才能覆盖更多的范围,
此时用新选择区间的左端点更新lastX的数据,继续遍历剩余的闭区间
*/
#include<cstdio>
#include<algorithm>
#pragma warning(disable:4996)
const int maxn = 110;
struct Interval {
int x, y; //闭区间左右端点
}I[maxn];
bool cmp(Interval a, Interval b) {
if (a.x != b.x) return a.x > b.x; //先按左端点从大到小排序
else return a.y < b.y; //左端点相同时,右端点小的在前
}
int main() {
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d%d", &I[i].x, &I[i].y);
}
std::sort(I, I + n, cmp); //对n个区间的端点大小排序
int point[maxn] = { 0 }, num = 0; //p[]存储要选择的点,长度最大为闭区间的数量(每个区间都选一个点),num是选中的点的个数
point[num++] = I[0].x; //第1个点选择区间左端点最大的这个点
int lastX = point[0]; //lastX记录上一个选择的区间的左端点
for (int i = 1; i < n; i++) { //遍历剩余的n-1个区间
if (I[i].y < lastX) { //待选区间右端点小于上一个被选中区间左端点,则两个区间范围不相交,待选区间符合要求
point[num++] = I[i].x; //将新选择区间的左端点存入point[]中
lastX = I[i].x; //更新lastX为新选择区间的左端点
}
}
for (int i = 0; i < num; i++) { //输出选中的点
printf("%d", point[i]);
if (i < num - 1) printf(" "); //除了最后一个点,其余后面加空格
}
return 0;
}