【刷题】贪心——区间问题:区间覆盖

文章目录

  • 模型
  • 算法
  • 正确性
  • 代码实现


模型

给定N个闭区间 [ a i , b i ] [a_i, b_i] [ai,bi]以及一个线段 [ s , t ] [s,t] [s,t],选择尽量少的区间,将线段完全覆盖。

第一行输入整数s和t,代表线段两个端点
第二行输入整数N,表示区间数
接下来N行输入整数 a i , b i a_i, b_i ai,bi,表示区间两个端点

输出一个整数,表示最少区间数
如果无解则输出-1

数据范围:
1 ≤ N ≤ 1 0 5 1 \leq N \leq 10^5 1N105
− 1 0 9 ≤ a i ≤ b i ≤ 1 0 9 -10^9 \leq a_i \leq b_i \leq 10^9 109aibi109
− 1 0 9 ≤ s ≤ t ≤ 1 0 9 -10^9 \leq s \leq t \leq 10^9 109st109


算法

将区间按端点从小到大排序,依次枚举每个区间。

  • 选择能覆盖s的区间里右端点最靠右的,不妨设这个右端点为last。
  • 继续枚举在剩下的区间,选择能覆盖last的区间中右端点最靠右的,更新last为这个右端点

正确性

设算法得到的区间的个数是A,最优解得到区间的个数是B

A = B A = B A=B
假设算法得到的区间如下: [ a 1 l , a 1 r ] , [ a 2 l , a 2 r ] , . . . , [ a m l , a m r ] [a_{1l}, a_{1r}], [a_{2l}, a_{2r}], ..., [a_{ml}, a_{mr}] [a1l,a1r],[a2l,a2r],...,[aml,amr]
假设最优解的区间如下: [ b 1 l , b 1 r ] , [ b 2 l , b 2 r ] , . . . , [ b m l , b m r ] [b_{1l}, b_{1r}], [b_{2l}, b_{2r}], ..., [b_{ml}, b_{mr}] [b1l,b1r],[b2l,b2r],...,[bml,bmr]
上面的区间按左端点从小到大排序,比较第一个不一样的区间,不妨设 [ a 2 l , a 2 r ] [a_{2l}, a_{2r}] [a2l,a2r] [ b 2 l , b 2 r ] [b_{2l}, b_{2r}] [b2l,b2r],那么一定有 a 2 r > b 2 r a_{2r}>b_{2r} a2r>b2r,因为算法选择的是右端点最靠右的区间。
因为最优解是合法的,所以有 b 3 l < b 2 r b_{3l}b3l<b2r,那么有 b 3 l < b 2 r < a 2 r b_{3l}b3l<b2r<a2r,因此可以拿 [ a 2 l , a 2 r ] [a_{2l}, a_{2r}] [a2l,a2r]替换 [ b 2 l , b 2 r ] [b_{2l}, b_{2r}] [b2l,b2r],并不会增加答案个数。
按照上述操作,拿A的区间依次替换B的区间,可以得到另一种最优解。


代码实现


题目链接

注意这题是考虑点覆盖而不是线段覆盖,例如[1, 3][4, 5]可以覆盖[1, 5],因此判断条件是range[j].l <= last + 1,并且r <= last时退出。
如果是线段覆盖则要改成range[j].l <= last,并且r < last时退出

#include 
#include 
using namespace std;

const int N = 25005;

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

int n, t;

int main() {
	scanf("%d%d", &n, &t);
	int st = 1, ed = t;
	//scanf("%d%d", &st, &ed);
	
	for (int i = 0; i < n; i ++ ) {
		scanf("%d%d", &range[i].l, &range[i].r);
	}
	sort(range, range + n);
	int ans = 0, last = st - 1;
	bool flag = false;
	for (int i = 0; i < n; i ++ ) {
		int j = i, r = 0;
		while (j < n && range[j].l <= last + 1) {
			r = max(r, range[j].r);
			j ++ ;
		}
		if (r <= last) {
			flag = false;
			break;
		}
		ans ++ ;
		if (r >= ed) {
			flag = true;
			break;
		}
		last = r;
		i = j - 1;
	}
	if (!flag) printf("-1");
	else printf("%d", ans);
	return 0;
}

你可能感兴趣的:(刷题,贪心算法,算法,数据结构)