【ETOJ P1035】小e看电视 题解(贪心算法)

题目描述

小e很喜欢看少儿频道,现在有n个动画片,第i个动画片每天以固定 [ l i , r i ] [l_i, r_i] [li,ri]的时间在全网播出,因为有很多电视台都在播出,所以时间可能重叠。

小e如果看一部动画片,就会从头看到尾,然后再去看另外一部。

也就是说,只要小e从 l i l_i li看到 r i r_i ri就算是看完了第i部动画片,换台不需要时间(中途不允许换台,在两端点位置允许换台)。

请问小e最多完整的看完多少个动画片?

注意,可能存在某些动画片一开始就结束( l i = r i l_i = r_i li=ri),此时小e只需疯狂快速换台即可看完。

输入格式

第一行一个整数n,表示动画片的个数。 ( 1 ≤ n ≤ 2 × 1 0 5 ) (1 \leq n \leq 2 \times 10^5) (1n2×105)

接下来n行,每行两个整数表示 l i , r i l_i, r_i li,ri ( 1 ≤ l i ≤ r i ≤ 1 0 9 ) (1 \leq l_i \leq r_i \leq 10^9) (1liri109)

输出格式

一个整数表示答案。

样例

输入1

5
1 4
5 6
7 9
3 6
8 10

输出1

3

解释: 可以选择看完第1, 2, 5这三部动画片。


思路

贪心算法,在给定的多个区间中选择尽可能多的不重叠区间。

首先,代码定义了一个全局变量nans,以及一个存储pair类型的向量v1n用于存储区间的数量,ans用于存储结果,v1用于存储所有的区间。

main函数中,首先读取区间的数量n,然后读取每一个区间的左右端点,并将它们以pair的形式存储在v1中。

接着,对v1进行排序,排序规则是先按照区间的右端点升序排序,如果右端点相同,那么再按照左端点升序排序。这是因为我们希望尽可能选择右端点小的区间,这样后面的空间就更大,可以选择更多的区间。

然后,遍历排序后的v1,对于每一个区间,如果它的左端点不小于当前的右端点pr,那么就选择这个区间,更新pr为这个区间的右端点,并将结果ans加1。否则,就跳过这个区间。

最后,输出结果ans,即最多可以选择的不重叠区间的数量。


AC代码

#include 
#include 
#include 
#define mp make_pair
#define ll long long
#define AUTHOR "HEX9CF"
using namespace std;

int n;
ll ans;
vector<pair<int, int>> v1;

bool cmp(pair<int, int> x, pair<int, int> y) {
	if (x.second == y.second) {
		return x.first < y.first;
	}
	return x.second < y.second;
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	cin >> n;
	for (int i = 1; i <= n; i++) {
		int l, r;
		cin >> l >> r;
		v1.push_back(mp(l, r));
	}

	sort(v1.begin(), v1.end(), cmp);

	ans = 0;
	auto it1 = v1.begin();
	int pr = 1;
	for (; it1 != v1.end(); it1++) {
		if (it1->first < pr) {
			continue;
		}
		pr = it1->second;
		ans++;
		// cout << it1->first << " " << it1->second << " " << pr << endl;
	}
	cout << ans << endl;
	return 0;
}

你可能感兴趣的:(Algorithm,Problems,算法)