夕拾算法进阶篇:2)贪心区间

来源:互联网 发布:反恐精英永恒python 编辑:程序博客网 时间:2024/06/05 15:07

1.问题引入

先引入一个问题:给出n个开区间,从中选择尽可能多的开区间,使得这些开区间两两没有交集。例如开区间(1,3)、(2,4)、(3,5)、(6,7),可以选择最多3个区间(1,3)、(3,5)、(6,7),它们互相没有交集。

首先考虑下比较简单的情况,如果开区间I1被开区间I2包含,如图a-1所示,显然选择I1是最后的选择,因为如果选择I1,那么就有更大的空间其容纳其他开区间。如果我们把开区间的所有左端点从大到小排序,不考虑区间包含的情况,那么定有y1>y2>...>yn,如图a-2所示,通过观察I1的右边有一段肯定是不会和其他区间重叠的,如果去掉它,I1的左边就会被I2包含,从而变成了图a-1的情形。因此,总是先选择左端点最大的区间。



对应不重叠的选区间问题,我们先看一个例题:

2.最多开区间问题

问题 A: 看电视
题目描述
暑假到了,小明终于可以开心的看电视了。但是小明喜欢的节目太多了,他希望尽量多的看到完整的节目。
现在他把他喜欢的电视节目的转播时间表给你,你能帮他合理安排吗?

输入
输入包含多组测试数据。每组输入的第一行是一个整数n(n<=100),表示小明喜欢的节目的总数。
接下来n行,每行输入两个整数si和ei(1<=i<=n),表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。
当n=0时,输入结束。

输出
对于每组输入,输出能完整看到的电视节目的个数。
样例输入

12
1 3
3 4
0 7
3 8
15 19
15 20
10 15
8 18
6 12
5 10
4 14
2 9
0

样例输出

5


依照上面先选择左端点最大的区间的思路,代码还是很好实现的:

#include <algorithm>#include <cstdio>using namespace std;struct Bean{int si;int ei;}; int compare(Bean a,Bean b){return a.si > b.si;}int main(){int n,i;Bean beans[101];while(scanf("%d",&n),n){for(i=0;i<n;i++)scanf("%d%d",&beans[i].si,&beans[i].ei);sort(beans,beans+n,compare); //按左端点降序 int count=1,lastX=beans[0].si; //最后一个已经选出 for(int i=1;i<n;i++){if(lastX>=beans[i].ei){ //最后一个的左端点不在前一个之内 lastX=beans[i].si; //更新最后一个左端点 count++;}}printf("%d\n",count);}} 

题目来源:http://www.codeup.cn/problem.php?cid=100000584&pid=0

2.区间选点问题 

与上面的问题类似的是区间选点问题 :给出n个闭区间[x,y],求最少需要确定多少个点才能使每个闭区间中至少存在一个点。例如闭区间[1,4]、 [2,6]、[5,7]来说,需要2个点(例如3、5)才能保证每个区间至少有一个点。

事实上,该问题和区间不相交的策略是一致的。首先,看图a-1,I1上的点肯定在I2上,因而选I1定没错。再看图a-2,每个区间都要存在一个点使其可以覆盖尽可能多的区间,显然对于I1来说,x1就是这样的点。换句话来说,只有把上面代码中lastX>=beans[i].ei修改成lastX>beans[i].ei即可用解决该问题 (若取等于,说明LastX在2个区间中都出现,但实际上只记1次就行了)

0 0
原创粉丝点击