贪心区间类型题目的解法 (C++)

贪心区间类型题目的解法

题目和思路均来自AcWing及其视频讲解
这个文章我当作笔记

区间选点

给定 N 个闭区间 [ai,bi],请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。

输出选择的点的最小数量。

读入区间, 将区间按端点从小到大的排序, 然后从前往后枚举区间

最大不相交区间数量

给定 N 个闭区间 [ai,bi],请你在数轴上选择若干区间,使得选中的区间之间互不相交(包括端点)。

输出可选取区间的最大数量。

读入区间, 将区间按端点从小到大的排序, 然后从前往后枚举区间

#include
#include

using namespace std;

typedef pair<int, int> PII;

const int N = 100010;

int n;

struct Edge {
	int l, r;
	bool operator< (const Edge & t) const {
		return r < t.r;
	}
}nums[N];

int main() {
	cin >> n;
	for (int i = 0; i < n; i++)
		scanf("%d%d", &nums[i].l, &nums[i].r);

	sort(nums, nums + n);

	int cnt = 0;
	int ed = -2e9;

	for (int i = 0; i < n; i++) {
		if (nums[i].l > ed) {
			ed = nums[i].r;
			cnt ++;
		}
	}

	cout << cnt << endl;
	return 0;

}

区间分组

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

输出最小组数。
  1. 将所有的区间以左端点从小到大的排序
  2. 从前往后处理每个区间, 判断能否将其放到某个现有的组中, 若能放,则放, 不能放则放到一个新的组
#include
#include
#include


using namespace std;

const int N = 100010;

int n;
struct Range{
	int l, r;
	bool operator< (const Range &w) const {
	return l < w.l;
	}
}range[N];

int main() {
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		int l, r;
		scanf("%d%d", &l, &r);
		range[i] = {l, r};
	}
	
	sort(range, range + n);
	
	priority_queue<int, vector<int>, greater<int>> store; 	// 维护每个组的最大的右端点
	for (int i = 0; i < n; i++) {
		auto r = range[i];
		if (store.empty() || store.top() >= r.l) store.push(r.r);
		else {
			int t = store.top();
			store.pop();
			store.push(r.r);
		}
	}
	cout << store.size();
	return 0;
	
}

区间覆盖

给定 N 个闭区间 [ai,bi] 以及一个线段区间 [s,t],请你选择尽量少的区间,将指定线段区间完全覆盖。

输出最少区间数,如果无法完全覆盖则输出 −1。
  1. 将左端点从小到大排序
  2. 从前往后依次枚举每个区间, 在所有能覆盖start的区间中选一个右端点最大的区间, 选完以后,将start更新成右端点的最大值
#include
#include

using namespace std;

const int N = 100010;

int n;
struct Range {
	int l, r;
	bool operator< (const Range &w) {
		return l < w.l;
	}
}range[N];

int main() {
	int st, ed;
	scanf("%d%d", &st, &ed);
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		int l, r;
		scanf("%d%d", &l, &r);
		range[i] = {l, r};
	}
	
	sort(range, range + n);
	
	int res = 0;
	bool success = false;
	for (int i = 0; i < n; i++) {
		int j = i, r = -2e9;
		while (j < n && range[j].l <= st) {
			r = max(r, range[j].r);
			j++;
		}
		
		if (r < st) {
			res = -1;
			break;
		}
		
		res++;
		
		if (r >= ed) {
			success = true;
			break;
		}
		
		st = r;
		
		i = j - 1;
	}
	
	if (!success) res = -1;
	cout << res << endl;
}

区间合并

给定 n 个区间 [li,ri],要求合并所有有交集的区间。

注意如果在端点处相交,也算有交集。

输出合并完成后的区间个数。
#include
#include

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 100010;

int n;
PII nums[N];


int main() {
	cin >> n;
	for (int i = 0; i < n; i++) {
		scanf("%d%d", &nums[i].x, &nums[i].y);
	}
	
	sort(nums, nums + n);
	
	int cnt = 0;
	int r = -1e9 - 10;
	for (int i = 0; i < n; i++) {
		if (nums[i].x > r) {
			cnt++;
			r = nums[i].y;
		} else {
			r = max(nums[i].y, r);
		}
	}
	cout << cnt << endl;
	return 0;
} 

你可能感兴趣的:(算法学习,c++,算法)