Week3--作业--C--区间覆盖 [贪心算法]

题目描述

数轴上有 n (1<=n<=25000)个闭区间 [ai, bi],选择尽量少的区间覆盖一条指定线段 [1, t] (1<=t<=1,000,000)。覆盖整点,即(1,2)+(3,4)可以覆盖(1,4)。不可能办到输出-1。

输入

第一行:N和T
第二行至N+1行:
每一行一个闭区间。

输出

  输出选择的区间的数目,
不可能办到输出-1

样例输入

3 10
1 7
3 6
6 10

样例输出

2

思路

综述

这个题和这周做的B题十分类似,也是将一个区间组合排序,然后依次选择;用到的算法也是贪心算法;
排序的准则是:按照按照右端点从头到尾的升序排列;

贪心的准则:

假定当前要覆盖的区间是[begin,end];闭区间)
下一次选择的区间满足以下条件:
1)区间的末端点大于于等于end;
2)区间的左端点是满足条件1中的最小的一个
如果某次选择没有可用区间,并且要覆盖的区间还未空,则退出返回-1,否则返回选择的区间的个数;

过程

Step1:输入

再输入的时候,进行一遍筛选,将右端点小于begin或者左端点大于end的清除

	for (i = 0; i < n; i++) {
		 P xx;
		cin >> xx.a >> xx.b;
		if (xx.a<1 || xx.b>t) continue;
		qq.push(xx);
	}
Step2:选择

第一步判断
右端点最大的是否大于等于end

	if (qq.top().b < t) {
		std::cout << "-1" << endl;
		return 0;
	}

循环选择:

		while (!qq.empty()) {
		if (qq.top().b >= t) {//找到右端点在end之后的
			if (qq.top().a < flag)
				flag = qq.top().a;//找出符合的点中左端点最小的一个
			if (flag <= 1) {
				total++;//已经覆盖整个区间,退出并且输出结果
				std::cout << total << endl;
				return 0;
			}
			qq.pop();
		}
		else {
		//找到之后进行更新
			t = flag - 1;
			flag = t;
			total++;//区间选择总数加一
			if (qq.top().b < t) {
				std::cout << "-1" << endl;
				return 0;
			}
		}
	}

总结

1、使用快速读入scanf可以节省时间
2、贪心的准则有很多,需要找出并且证明一个正确的
记录:(刚开始错误的想法)
错误1:在多关键字排序的时候,排序的准则如下
1、右端点需要大于等于t
2、左端点小的排在前面
但是这样是错误的,因为更新过一次之后,再选择区间的时候,就会选择出并不符合题意的区间
错误2:在错误1的基础上优化,但是优化方式不对,导致超时
错误优化:每次选择完区间都进行重新排序,右端点大于等于当前要覆盖的区间的end,这样复杂度在O(n^2*log)级别上,严重超时。

代码

#include <iostream>
#include <stdio.h>
#include <queue>
using namespace std;
int t;
int total = 0;
struct P {
	int a, b;
	bool operator <(const struct P& p)const {
		return b < p.b;
	}
};
int main() {
	int n, i;
	cin >> n >> t;
	priority_queue<P> qq ;
	//读入数据
	for (i = 0; i < n; i++) {
		 P xx;
		cin >> xx.a >> xx.b;
		//初步筛选
		if (xx.a<1 || xx.b>t) continue;
		qq.push(xx);
	}
	int step = 1;
	//初步判断
	if (qq.top().b < t) {
		std::cout << "-1" << endl;
		return 0;
	}
	int flag = 1000000;
	while (!qq.empty()) {
	//选点
		if (qq.top().b >= t) {
		//找出最优的点
			if (qq.top().a < flag)
				flag = qq.top().a;
			if (flag <= 1) {
				total++;
				std::cout << total << endl;
				return 0;
			}
			qq.pop();
		}
		else {
			t = flag - 1;
			flag = t;
			total++;//更新
			if (qq.top().b < t) {
				std::cout << "-1" << endl;
				return 0;
			}
		}
	}

	//不行
	std::cout << "-1" << endl;


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

猜你喜欢

转载自blog.csdn.net/weixin_44552961/article/details/104989061