每日一题之 hiho223周 Interval Coverage

描述
You are given N intervals [S1, T1], [S2, T2], [S3, T3], … [SN, TN] and a range [X, Y]. Select minimum number of intervals to cover range [X, Y].

输入
The first line contains 3 integers N, X and Y. (1 <= N <= 100000, 1 <= X < Y <= 1000000)

The following N lines each contain 2 integers Si, Ti denoting an interval. (1 <= Si < Ti <= 1000000)

输出
Output the minimum number of intevals to cover range [X, Y] or -1 if it is impossible.

样例输入
5 1 5
1 2
1 3
2 4
3 5
4 5
样例输出
2

题意:

给n个区间 以及一个目标区间,问n个区间中最少可以由几个区间可以把目标区间覆盖。

思路:

一开始以为可以用dfs来做,每个区间起点和终点连边然后dfs求一个最短路径。后面发现,目标区间得起点,不一定是给定区间得起点,所以不能用这方法做。
正解是贪心。
具体来说,可以用以下贪心思路解决本题:

首先找到一个起点 <= X,并且终点尽量大(靠右)的区间,选为第一个区间。不妨设这个区间的终点是R[1]。

然后再找一个起点 <= R[1],并且终点尽量大的区间,选为第二个区间。不妨设这个区间的终点是R[2]。

重复以上步骤,直到某个R[k]满足R[k] >= Y,这时R[1] … R[k]即是一组最优的区间,k即是答案。

如果在中间某一步发现R[k] == R[k-1],说明做不到覆盖整个[X, Y],输出-1。

以上贪心算法最关键的就是找起点 <= 某个值,同时终点尽量大的区间。

我们可以将所有区间按起点排序,然后从头到尾扫描即可完成以上的查找。复杂度是排序O(NlogN) + 扫描贪心O(N)。

#include <bits/stdc++.h>

using namespace std;

struct Node {
	int x,y;
};

vector<Node>A;

bool cmp(Node a, Node b) {
	if (a.x == b.x) return a.y < b.y;
	return a.x < b.x;
}

void solve(vector<Node>&A,int s, int t) {
	sort(A.begin(),A.end(),cmp);
	int res = 0;
	vector<Node>B;
	int idx = 0;
	int nows = s;
	int nowt = 0;
	int i;
	while(1) {
		for (i = idx; i < (int)A.size(); ++i) {
			if (A[i].x <= s && A[i].y > nowt) {
				nows = A[i].x;
				nowt = A[i].y;
				idx = i;
			}
		}
		++res;
		Node tmp;
		tmp.x = nows;
		tmp.y = nowt;
		//cout << nows << " " << nowt << " "<< idx <<  endl;
		if (B.size() != 0 && B.back().y == tmp.y) {
			cout << "-1"<<endl;
			return;
		}
		B.push_back(tmp);
		if (nowt >= t) break;
		else { 
			idx = idx+1;
			s = nowt;
		}
	}

	if (nowt < t) cout << "-1"<<endl;
	else
		cout << res << endl;
}


int main () {

	int n,s,t,x,y;
	cin >> n >> s >> t;
	for (int i = 0; i < n; ++i) {
		cin >> x >> y;
		Node tmp;
		tmp.x = x;
		tmp.y = y;
		A.push_back(tmp);
	}

	solve(A,s,t);


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值