贪心——区间贪心

1.区间不相交问题

给出N个开区间(x,y),从中选择尽可能多的开区间,使得这些开区间两两没有交集。以下两种选择都可以实现

(1)总是先选择左端点最大的区间

#include <cstdio>
#include <algorithm>
using namespace std;
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;
	while(scanf("%d", &n), n != 0){
		for(int i = 0; i<n; i++){
			scanf("%d%d", &I[i].x, &I[i].y);
		}
		sort(I, I+n, cmp);
		int ans = 1,lastX = I[0].x;  //ans记录不相交区间个数,lastX记录上一个被选中区间的左端点
		for(int i = 1; i < n; i++){
			if(I[i].y <= lastX){  //如果该区间右端点在lastX左边
				lastX = I[i].x;  //以I[i]作为新选中的区间
				ans++;
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

(2)总是先选择右端点最小的区间

#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 110;
struct Interval{
	int x, y;  //开区间左右端点 
}I[maxn];
bool cmp(Interval a, Interval b){
	if(a.y != b.y) return a.y < b.y;  //先按右端点从小到大排序
	else return a.x > b.x;            //右端点相同的按左端点从大到小排序
}
int main()
{
	int n;
	while(scanf("%d", &n), n != 0){
		for(int i = 0; i<n; i++){
			scanf("%d%d", &I[i].x, &I[i].y);
		}
		sort(I, I+n, cmp);
		int ans = 1,lastY = I[0].y;  //ans记录不相交区间个数,lastY记录上一个被选中区间的右端点
		for(int i = 1; i < n; i++){  //如果该区间左端点在lastY右边
			if(I[i].x >= lastY){  //以I[i]作为新选中的区间
				lastY = I[i].y;  
				ans++;
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

2.区间选点问题

给出N个闭区间[x,y],求最少需要确定多少个点,才能使每个闭区间中都至少存在一个点

(1)总是先选择左端点最大的区间

#include <cstdio>
#include <algorithm>
using namespace std;
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;
	while(scanf("%d", &n), n != 0){
		for(int i = 0; i<n; i++){
			scanf("%d%d", &I[i].x, &I[i].y);
		}
		sort(I, I+n, cmp);
		int ans = 1,lastX = I[0].x;  //ans记录点数,lastX记录上一个被选中的端点
		for(int i = 1; i < n; i++){  
			if(I[i].y < lastX){    //如果该区间右端点在lastX左边,此处与上面不同
				lastX = I[i].x;     //以I[i]作为新选中的区间
				ans++;
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

(2)总是先选择右端点最小的区间

#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 110;
struct Interval{
	int x, y;  //开区间左右端点 
}I[maxn];
bool cmp(Interval a, Interval b){
	if(a.y != b.y) return a.y < b.y;  //先按右端点从小到大排序
	else return a.x > b.x;            //右端点相同的按左端点从大到小排序
}
int main()
{
	int n;
	while(scanf("%d", &n), n != 0){
		for(int i = 0; i<n; i++){
			scanf("%d%d", &I[i].x, &I[i].y);
		}
		sort(I, I+n, cmp);
		int ans = 1,lastY = I[0].y;  //ans记录点数,lastY记录上一个被选中的右端点
		for(int i = 1; i < n; i++){  //如果该区间左端点在lastY右边
			if(I[i].x > lastY){  //以I[i]作为新选中的区间,此处与上面不同
				lastY = I[i].y;  
				ans++;
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Highlight_Jin/article/details/88921199