Week3--作业--B - 区间选点[贪心算法]

题目描述

数轴上有 n 个闭区间 [a_i, b_i]。取尽量少的点,使得每个区间内都至少有一个点(同区间内含的点可以是同一个)。

输入

  第一行1个整数N(N<=100)
第2~N+1行,每行两个整数a,b(a,b<=100)

输出

  一个整数,代表选点的数目

样例输入

2
1 5
4 6

样例输出

1

思路

综述

这道题用到两个知识:多关键字排序和贪心算法
对于多关键字排序:
关键字1:区间的第二个端点,按照从头到尾的升序排列
关键字2:区间的第一个端点,按照从头到尾的降序排列
贪心算法:
按照上述排序好的区间:优先选择第一个区间的最后一个点,然后对区间已经合法的去除,再从剩下的区间内,选择第一个区间的最后一个端点
证明:
顺着推:按照上述排序之后:
如下图:第一个点的选择既可以是b点,也可以是a到b之间的任意一个,从这里来看b点是最优的选择,因为选择b点可以拆除3个区间,
循环得出答案;
在这里插入图片描述

过程

Step1:输入

结构体 P
a,b是两个端点值

struct P {
	int a, b;
	bool operator < (const struct P& p)const {
		if (b != p.b) return b > p.b;//第一个最小  降序
		return a < p.a;//第一个最大  升序
	}
};

qq是优先队列,里面元素是结构体P

	for (i = 0; i < n; i++) {
		cin >> x.a >> x.b;
		qq.push(x);
	}
Step2:选点

从堆第一个选出一个点;
对堆里面的可清除的点进行剔除;

		while (!qq.empty()) {
			int num = qq.top().b;
			total++;
			while (!qq.empty()) {
				if (qq.top().a > num)break;
				qq.pop();
			}
		}

总结

深入思考
下面是,没有利用多关键字排序的结果,对于评测机,可以过;
也就是排序的时候,没考虑第一个端点的情况,细细思考,在选点的过程中也是没有用到第一个点。只是在排序的时候,徒增复杂度。
在这里插入图片描述
如下图:框出的是
没有多关键字排序的时间但是,时间更慢了,具体原因机器本身性能波动。
在这里插入图片描述

代码

#include <iostream>
#include <queue>
using namespace std;
int total = 0;
struct P {
	int a, b;
	bool operator < (const struct P& p)const {
		if (b != p.b) return b > p.b;//第一个最小  降序
		return a < p.a;//第一个最大  升序
	}
};
int main() {
	priority_queue<P>  qq;
	struct P x;
	int n, i, j;
	cin >> n;
	for (i = 0; i < n; i++) {
		cin >> x.a >> x.b;
		qq.push(x);
	}
		while (!qq.empty()) {
		//选点
			int num = qq.top().b;
			total++;
			//剔除
			while (!qq.empty()) {
				if (qq.top().a > num)break;
				qq.pop();
			}
		}
	cout << total << endl;

}
发布了29 篇原创文章 · 获赞 14 · 访问量 1257

猜你喜欢

转载自blog.csdn.net/weixin_44552961/article/details/104985563
今日推荐