区间贪心_区间选点问题

点击查看代码
/*
给出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;
}
posted @ 2022-09-30 22:54  zhaoo_o  阅读(7)  评论(0编辑  收藏  举报