贪心算法: 区间分组

c++

区间分组


/*
问题描述:
	给定 N 个闭区间 [ai,bi],请你将这些区间分成若干组,使得每组内部的区间两两之间(包括端点)没有交集,并使得组数尽可能小。
	输出最小组数。

	输入格式:
	第一行包含整数 N,表示区间数。
	接下来 N 行,每行包含两个整数 ai,bi,表示一个区间的两个端点。

	输出格式:
	输出一个整数,表示最小组数。

	数据范围:
	1 ≤ N ≤ 105,
	−10^9 ≤ ai ≤ bi ≤ 10^9

解题思路:
	区间按照左端点排序。然后,我们按照 1->n 遍历数组(最短点是依次增大的)
	对于 i
		我们假设当前已经存在 x 组区间,这些 x 组的区间,每组最靠右的区间为 [left_1, right_1], ..., [left_x, right_x]
		根据我们的区间左端点排序,可知 segments[i].first > 任意 left_t, t属于[1, x]闭区间,也就是说,我们需要查看 right 的情况,判断 区间 i 是否可以放入集合中
		倘若存在任意一个 right_j 严格小于 segments[i].first,则可以插入,否则需要增加一个新的区间集合。
		倘若存在 right_j 个区间,我们需要选择哪一个呢?答案是任意一个,因为 segments[i].first <= segments[i+1].first, 
		这里面的任何一个区间对于剩下的 segments集合都是 ok 的。
	但是,当然是选取最小的一个好了,因为使用堆维护,非常方便

	证明可以通过替换法来证明,不过需要每次需要替换一整个后面的序列,由任何一个解交换为同样最优的解题思路给出的解。
 */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>

using namespace std;

const int N = 100010;
typedef pair<int, int> PII;

PII segments[N];
int n;


bool cmp(const PII &t1, const PII &t2) {
	return t1.first <= t2.first;
}


int solution_one() {
	int res = 0;
	priority_queue<int, vector<int>, greater<int> > pque;
	sort(segments + 1, segments + n + 1, cmp);


	for (int i = 1; i <= n; i ++ ) {
		if (pque.empty() == true) {
			pque.push(segments[i].second);
			res += 1;
		} else if (pque.top() < segments[i].first) {
			pque.pop();
			pque.push(segments[i].second);
		} else {
			pque.push(segments[i].second);
			res += 1;
		}
	}


	return res;	// pque.size();
}


int main()
{
	// input
	scanf("%d", &n);
	for (int i = 1; i <= n; i ++ ) {
		scanf("%d%d", &segments[i].first, &segments[i].second);
	}

	int res = solution_one();

	printf("%d\n", res);

	return 0;
}


posted @ 2022-07-15 21:37  lucky_light  阅读(368)  评论(0编辑  收藏  举报