三类基于贪心思想的区间覆盖问题

一、区间完全覆盖问题

问题描述:给定一个长度为m的区间,再给出n条线段的起点和终点(注意这里是闭区间),求最少使用多少条线段可以将整个区间完全覆盖。

样例:一个长度为8的区间,可选的线段有[2,6],[1,4],[3,6],[3,7],[6,8],[2,4],[3,5]。

求解过程:

1、将每一条线段按左端点递增顺序排列,如果左端点相同,按右端点递增顺序排列,排完序后为[1,4],[2,4],[2,6],[3,5],[3,6],[3,7],[6,8];

2、设置一个变量表示已覆盖到的区间右端点,在剩下的线段中找出所有左端点小于等于当前已覆盖到的区间右端点的线段,选择右端点最大并且大于当前已覆盖到的区间右端点,重复以上操作直至覆盖整个区间;

3、模拟过程:假设第一次加入[1,4],那么下一次能够选择的线段有[2,6],[3,5],[3,6],[3,7],由于3小于4且7最大,所以下一次选择[3,7]进行覆盖,最后一次只能选择[6,8],这个时候刚好覆盖长为8的区间-->break;即所选3条线段就能覆盖长度为8的大区间;

4、贪心证明:

要求用最少的线段进行覆盖,那么选取的线段必然要尽量长,而已覆盖到的区域之前的地方已经不用考虑了,可以理解成所有可覆盖的左端点都已被覆盖了,那么能够使得线段更长的取决于右端点,左端点没有太大的意义,所以选择右端点来覆盖。

题解报告:NYOJ #12 喷水装置(二)

描述

有一块草坪,横向长w,纵向长为h,在它的橫向中心线上不同位置处装有n(n<=10000)个点状的喷水装置,每个喷水装置i喷水的效果是让以它为中心半径为Ri的圆都被润湿。请在给出的喷水装置中选择尽量少的喷水装置,把整个草坪全部润湿。

输入

第一行输入一个正整数N表示共有n次测试数据。每一组测试数据的第一行有三个整数n,w,h,n表示共有n个喷水装置,w表示草坪的横向长度,h表示草坪的纵向长度。随后的n行,都有两个整数xi和ri,xi表示第i个喷水装置的的横坐标(最左边为0),ri表示该喷水装置能覆盖的圆的半径。

输出

每组测试数据输出一个正整数,表示共需要多少个喷水装置,每个输出单独占一行。如果不存在一种能够把整个草坪湿润的方案,请输出0。

样例输入

2
2 8 6
1 1
4 5
2 10 6
4 5
6 5

样例输出

1
2
解题思路:典型的区间完全覆盖问题。由于喷水装置是安置在横向中心线上并且圆具有对称性,故只需取高度的一半,然后将每个喷水装置能够覆盖的区间范围映射成在x轴的长度,然后按上面的方法贪心选线段即可。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=10005;
 4 int t,n,k,cnt,pos,beg;double w,h,lb,xi,ri,maxv;pair<double,double> itv[maxn];bool flag;
 5 int main(){
 6     while(cin>>t){
 7         while(t--){
 8             cin>>n>>w>>h;h/=2.0;pos=cnt=0;//h取一半
 9             for(int i=0;i<n;++i){
10                 cin>>xi>>ri;
11                 if(ri<h)continue;//ri==h也要算
12                 itv[pos].first=xi-sqrt(ri*ri-h*h);
13                 itv[pos++].second=xi+sqrt(ri*ri-h*h);
14             }
15             sort(itv,itv+pos);lb=0;beg=0;flag=false;
16             if(itv[0].first>0){cout<<0<<endl;continue;}//按左端点排序只需查看最左边的端点是否满足条件即可,最右边的端点在下面有判断
17             while(lb<w){
18                 maxv=0;
19                 for(k=beg;k<pos&&itv[k].first<=lb;++k)//itv[k].first<=lb这样保证整个区间是连续的,即草坪都会被润湿
20                     maxv=max(maxv,itv[k].second);//找线段左端点在lb以内右端点能覆盖到的最远距离
21                 if(maxv>lb)cnt++,lb=maxv,beg=k;//如果有一条线段右端点比当前已覆盖的区间右端点lb还大,那么就更新已覆盖的右端点值,同时计数器加1
22                 else {flag=true;break;}//否则说明不能覆盖整个区间,直接退出,输出0
23             }
24             if(flag)cout<<0<<endl;
25             else cout<<cnt<<endl;
26         }
27     }
28     return 0;
29 }

题解报告:NYOJ #6 喷水装置(一)

描述

现有一块草坪,长为20米,宽为2米,要在横中心线上放置半径为Ri的喷水装置,每个喷水装置的效果都会让以它为中心的半径为实数Ri(0<Ri<15)的圆被湿润,这有充足的喷水装置i(1<i<600)个,并且一定能把草坪全部湿润,你要做的是:选择尽量少的喷水装置,把整个草坪的全部湿润。

输入

第一行m表示有m组测试数据;每一组测试数据的第一行有一个整数数n,n表示共有n个喷水装置,随后的一行,有n个实数ri,ri表示该喷水装置能覆盖的圆的半径。

输出

输出所用装置的个数

样例输入

2
5
2 3.2 4 4.5 6 
10
1 2 3 1 2 1.2 3 1.1 1 2

样例输出

2
5
解题思路:将每个能喷洒到草坪边缘的喷水装置的喷洒范围映射成在x轴的长度,然后按线段长度递增顺序排列,再从后往前贪心选线段即可得到选择最少的喷水装置来润湿整个草坪。AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int t,n,cnt;double ans,ri,dt[605];
 4 int main(){
 5     while(cin>>t){
 6         while(t--){
 7             cin>>n;ans=0;cnt=0;
 8             for(int i=0;i<n;++i)cin>>ri,dt[i]=ri>1?sqrt(ri*ri-1):0;//这里可以设置为0,因为题目已经保证一定可以将草坪全部润湿
 9             sort(dt,dt+n);
10             for(int i=n-1;ans<=10.0&&i>=0;--i)cnt++,ans+=dt[i];//从后往前能选出最少数量的喷水装置,且一定能将草坪润湿
11             cout<<cnt<<endl;
12         }
13     }
14     return 0;
15 }

 二、最大不相交区间数问题

问题描述:数轴上有n个区间$ [a_i,b_i] $,要求选择尽量多个区间,使得这些区间两两没有公共点。

样例:数轴上有7个区间,可选的区间有[2,6],[1,4],[3,6],[3,7],[6,8],[2,4],[3,5]。

求解过程:

1、按区间右端点递增顺序排列,如果右端点相同,按左端点递增顺序排序,排完序后为[1,4],[2,4],[3,5],[2,6],[3,6],[3,7],[6,8];
2、第一次选择[1,4],接下来只能选择[6,8],即当前数轴上最多只能选择两个不相交的区间。

3、贪心证明:为了选择更多的区间个数,先按区间右端点递增顺序排列,然后顺序处理每个区间,如果它与当前已选的所有区间都没有相交,则选择该区间,否则不选。接下来证明区间左端点a1,a2…对右端点没有影响:

①当a1>a2时,区间2包含区间1,显然不能选择区间2,因为选择区间1会留下更多的区域。不仅区间2如此,以后所有区间中只要有一个i满足a1>ai,i都不要选,所以此种情况下,选择区间1是明智的,与策略一致。

②排除情况1后,一定有a1<=a2<=a3……,此时选择区间1是最优策略,说明无论左端点是大是小,只要对区间右端点进行排序,然后贪心选择不相交的区间就可得到数轴上最多不相交的区间个数,即这个策略是正确的。

 

题解报告:NYOJ #14 会场安排问题

描述

学校的小礼堂每天都会有许多活动,有时间这些活动的计划时间会发生冲突,需要选择出一些活动进行举办。小刘的工作就是安排学校小礼堂的活动,每个时间最多安排一个活动。现在小刘有一些活动计划的时间表,他想尽可能的安排更多的活动,请问他该如何安排。

输入

第一行是一个整型数m(m<100)表示共有m组测试数据。
每组测试数据的第一行是一个整数n(1<n<10000)表示该测试数据共有n个活动。
随后的n行,每行有两个正整数Bi,Ei(0<=Bi,Ei<10000),分别表示第i个活动的起始与结束时间(Bi<=Ei)

输出

对于每一组输入,输出最多能够安排的活动数量。
每组的输出占一行

样例输入

2
2
1 10
10 11
3
1 10
10 11
11 20

样例输出

1
2
解题思路:按结束时间早进行排序,然后贪心选择不相交区间即可。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const int maxn=10005;
 5 int t,n,tmp,ans;pair<int,int> itv[maxn];
 6 int main(){
 7     while(cin>>t){
 8         while(t--){
 9             cin>>n;
10             for(int i=0;i<n;++i)cin>>itv[i].second>>itv[i].first;
11             sort(itv,itv+n);tmp=-1;ans=0;//按结束时间早进行排序
12             for(int i=0;i<n;++i)
13                 if(tmp<itv[i].second)ans++,tmp=itv[i].first;
14             cout<<ans<<endl;
15         }
16     }
17     return 0;
18 }

三、区间选点问题

问题描述:数轴上有n个闭区间 $[a_i,b_i] $,要求选取尽量少的点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个)。

样例略。

求解过程:

1、按左端点递增顺序排序,如果左端点相同,按右端点递增顺序排序,个人觉得这种比较好理解,当然也可以按右端点递增顺序排序。

2、①从第一个区间右端点开始贪心往后找,如果下一个区间的左端点大于当前已选区间的右端点,说明要新开一个点,计数器加1,同时更新右区间能覆盖的最远距离;②如果下一个区间右端点小于当前已选区间的右端点,说明共享的线段范围缩短了,那么就更新区间右端点为下一个区间右端点,重复以上操作,直至筛选完所有区间。

贪心证明:为了选择最少的点使得每个区间内至少含有一个点,考虑按区间左端点递增顺序排序,如果左端点相同,则按区间右端点递增顺序排序,然后以第一个区间右端点作为第一个点能覆盖的最大范围。①当b1>b2时,显然此时一个点能覆盖最大的区域右边界变为b2,同理,以后只要满足 $ b_1 > b_i $,一个点能覆盖的区域右边界就会变为 $ b_i $,显然这是正确的;②当b1<a2时,显然一个点不能覆盖到区间2上,所以需新开一个点,此时能覆盖的区域最右边界变为b2,同理,以后只要满足 $ b1 < a_i $,则都要新开一个点,并且其能覆盖的区域右边界将变为 $ b_i $,显然这也是正确的;③ 当b1<b2时,显然区间1和区间2有公共的部分,但此时一个点能覆盖的区域最右边界还是为 b1,无需更新区域最右边界,同理,对于以后只要满足 $ b_1<b_i $,都无需新开一个点,也无需更新能覆盖区域的最右边界,显然这也是正确的。综上,按区间左端点递增的顺序排序,再按规则贪心选点的策略是正确的。

题解报告:NYOJ #891 找点

描述

上数学课时,老师给了LYH一些闭区间,让他取尽量少的点,使得每个闭区间内至少有一个点。但是这几天LYH太忙了,你们帮帮他吗?

输入

多组测试数据。
每组数据先输入一个N,表示有N个闭区间(N≤100)。
接下来N行,每行输入两个数a,b(0≤a≤b≤100),表示区间的两个端点。

输出

输出一个整数,表示最少需要找几个点。

样例输入

4
1 5
2 4
1 4
2 3
3
1 2
3 4
5 6
1
2 2

样例输出

1
3
1
解题思路:按左端点递增顺序排序,然后按上面的求解方法贪心选点即可。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const int maxn=105;
 5 int n,tmp,ans;pair<int,int> itv[maxn];
 6 int main(){
 7     while(cin>>n){
 8         for(int i=0;i<n;++i)cin>>itv[i].first>>itv[i].second;
 9         sort(itv,itv+n);tmp=itv[0].second;ans=1;
10         for(int i=0;i<n;++i){
11             if(tmp<itv[i].first)ans++,tmp=itv[i].second;
12             else if(tmp>itv[i].second)tmp=itv[i].second;
13         }
14         cout<<ans<<endl;
15     }
16     return 0;
17 }

题解报告:poj 1328 Radar Installation

Description

Assume the coasting is an infinite straight line. Land is in one side of coasting, sea in the other. Each small island is a point locating in the sea side. And any radar installation, locating on the coasting, can only cover d distance, so an island in the sea can be covered by a radius installation, if the distance between them is at most d. 
We use Cartesian coordinate system, defining the coasting is the x-axis. The sea side is above x-axis, and the land side below. Given the position of each island in the sea, and given the distance of the coverage of the radar installation, your task is to write a program to find the minimal number of radar installations to cover all the islands. Note that the position of an island is represented by its x-y coordinates. 
 
Figure A Sample Input of Radar Installations

Input

The input consists of several test cases. The first line of each case contains two integers n (1<=n<=1000) and d, where n is the number of islands in the sea and d is the distance of coverage of the radar installation. This is followed by n lines each containing two integers representing the coordinate of the position of each island. Then a blank line follows to separate the cases. 
The input is terminated by a line containing pair of zeros 

Output

For each test case output one line consisting of the test case number followed by the minimal number of radar installations needed. "-1" installation means no solution for that case.

Sample Input

3 2
1 2
-3 1
2 11 2
0 20 0

Sample Output

Case 1: 2
Case 2: 1
解题思路:典型的区间选点,将雷达能覆盖的范围映射为x轴上的线段长度,然后贪心区间选点即可。
AC代码:
 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cmath>
 4 using namespace std;
 5 const int maxn=1005;
 6 int n,d,ans,pos,cnt=1,x,y;double tmp;
 7 struct node{double l,r;}point[maxn];
 8 bool cmp(node a,node b){return a.l<b.l;}
 9 int main(){
10     while(cin>>n>>d&&(n|d)){//注意这里:n|d,表示n和d同时为0时,程序才退出
11         ans=1;pos=0;
12         for(int i=0;i<n;++i){
13             cin>>x>>y;
14             if(y>d){ans=-1;continue;}//根号下只能为非负数
15             point[pos].l=1.0*x-sqrt(1.0*d*d-y*y);//以每个岛屿为圆心,半径为d画圆,其与x轴最后只有两个交点
16             point[pos++].r=1.0*x+sqrt(1.0*d*d-y*y);
17         }
18         sort(point,point+pos,cmp);tmp=point[0].r;
19         for(int i=1;i<pos&&ans!=-1;++i){
20             if(tmp<point[i].l){ans++;tmp=point[i].r;}//如果已选线段与当前线段不相交,那么就设置一个新的雷达,然后更新tmp为其右端点值
21             else if(tmp>point[i].r)tmp=point[i].r;//可以覆盖掉下一条线段,但此时区间右端点缩短为下一条线段的右端点,说明覆盖的范围缩短了
22         }
23         cout<<"Case "<<cnt++<<": "<<ans<<endl;
24     }
25     return 0;
26 }

 

转载于:https://www.cnblogs.com/acgoto/p/9824723.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/450956.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu 常用软件和命令

永久修改屏幕的分辨率   sudo gedit .profile 将下面的四句话加入。.profile文件的最后   cvt 1280 768   xrandr --newmode "1280x768_60.00" 79.50 1280 1344 1472 1664 768 771 781 798 -hsync vsync   xrandr --addmode Virtual1 "1280x768_60.00&q…

Eclipse搭建Android开发环境(安装ADT,Android4.4.2)

见&#xff1a;http://blog.csdn.net/zht666/article/details/29837777 使用Eclipse做Android开发&#xff0c;需要先在Eclipse上安装ADT&#xff08;Android Development Tools&#xff09;插件。 1.安装JDK 1.7 JDK官网http://www.oracle.com/technetwork/java/javase/downlo…

C语言 位操作简析

位运算 前面介绍的各种运算都是以字节作为最基本位进行的。 但在很多系统程序中常要求在位(bit)一级进行运算或处理。&#xff23;语言提供了位运算的功能&#xff0c; 这使得&#xff23;语言也能像汇编语言一样用来编写系统程序。 一、位运算符&#xff23;语言提供了六种位运…

算法:输入一个链表,输出该链表中倒数第k个结点。

算法&#xff1a;输入一个链表&#xff0c;输出该链表中倒数第k个结点。《剑指offer》 思路加到注释里面了&#xff1b; 1&#xff1a;两个if判断是否返回值为空&#xff0c;首个为空&#xff0c;没有第k个值&#xff1b; 2&#xff1a;for循环找到倒数第k个值&#xff0c;返回…

Spring事务那些事儿

&#xff08;一&#xff09;事务的隔离级别 大家都知道事务有四个属性&#xff0c;即ACID&#xff08;原子性、一致性、隔离性、持久性&#xff09;。这四个里面稍微难理解点的是一致性和持久性。所谓的一致性是指&#xff1a;事务执行前后数据的一致性状态&#xff0c;例如事…

Silverlight Blend动画设计系列八:拖放(Drag-Drop)操作与拖放行为(DragBehavior)

Silverlight & Blend动画设计系列八&#xff1a;拖放(Drag-Drop)操作与拖放行为(DragBehavior) 原文:Silverlight & Blend动画设计系列八&#xff1a;拖放(Drag-Drop)操作与拖放行为(DragBehavior)在Silverlight中自身并没有提供拖放功能的相关实现&#xff0c;要实现拖…

mysql查询显示行号

见&#xff1a;http://blog.csdn.net/muzizhuben/article/details/49449853 使用mysql查询显示行号&#xff0c;没有像oracle这么方便。 不过也可以通过设定变量显示行号&#xff0c;例如&#xff1a; -- 生成 行号 select r:r1 as rowno , a.* from my_tb a ,(select r:0) b …

scanf 用法大全

关于标准库函数scanf论坛上很多人对scanf的不太了解&#xff0c;导致程序出错&#xff0c;我想把scanf的具体用法贴出来&#xff0c;希望大家可以共同进步&#xff0c;有什么不对的地方可以提出来。int scanf(char *format&#xff0c;...);这应该是scanf的标准形式。先说说关于…

深入了解Spring IoC

IoC全称Inversion of Control即控制反转&#xff0c;它还有一个别名依赖注入。spring利用Ioc容器帮我们自动构建对象及注入依赖对象&#xff0c;减少了对象构建与业务代码的耦合&#xff0c;使得我们能够更加高效愉快的写bug&#x1f41e;了(&#xffe3;▽&#xffe3;)"…

软文营销实战记录

最近拜读了徐茂权老师的《 网络营销决胜武器(第2版)》&#xff0c;下面会梳理书中的内容&#xff0c;记录下以后可能会用到的软文营销的技巧。 一、软文载体 1、平面媒体软文&#xff1a;报纸、期刊。 2、非正式出版的基于印刷、打印形式载体的软文&#xff1a;企业印刷的宣传册…

oracle中rownum和row_number()的区别

见&#xff1a;http://www.jb51.net/article/65960.htm row_number()over(partition by col1 order by col2)表示根据col1分组&#xff0c;在分组内部根据col2排序&#xff0c;而此函数计算的值就表示每组内部排序后的顺序编号&#xff08;组内连续的唯一的&#xff09;。 与ro…

java类加载顺序

在java中类的加载、初始化都是在程序运行期完成的&#xff0c;虽然会稍微增加开销&#xff0c;但是却很大的增加了灵活性&#xff0c;我们可用在运行期间动态的去网络或其他地方加载一个二进制流来作为程序代码的一部分。接下来我们简单介绍下java类加载过程。 从上图中我们可…

dealloc不调用的情况

2019独角兽企业重金招聘Python工程师标准>>> 1、没有停止定时器 - (void)dealloc { [_timer invalidate]; _timer nil; } 2、VC中有代理Delegate&#xff0c;需要设置delegate的时候&#xff0c;设置为weak property (nonatomic,weak) id<ZoeEatDe…

day10-列表生成式

列表生成式即List Comprehensions&#xff0c;是Python内置的非常简单却强大的可以用来创建list的生成式。 1、生成一个列表 a [i for i in range(1,100) if i%21]print(list(a))或print(a)[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, …

jrebel、JavaRebel

见&#xff1a;https://baike.baidu.com/item/jrebel/1115725?fraladdin JRebel是一套JavaEE开发工具。中文名jrebel属 性JavaEE开发工具资 费收费软件作 用Jrebel 可快速实现热部署JRebel是一套JavaEE开发工具。JRebel允许开发团队在有限的时间内完成更多的任务修正…

自己写函数库

大家现在写 程序&#xff0c;是不是都是用新唐提供的函数库&#xff1f;在体验 开发板的一开始&#xff0c;我也是使用函数库&#xff0c;毕竟这个太方便了。可是有一天&#xff0c;我发现一个只使用时钟和IO以及 调试 串口的程序居然查过了16k的时候&#xff0c;我震惊了&…

[MicroPython]stm32f407控制DS18B20检测温度

2019独角兽企业重金招聘Python工程师标准>>> 1.实验目的 1. 学习在PC机系统中扩展简单I/O 接口的方法。 2. 进一步学习编制数据输出程序的设计方法。 3. 学习DS18B20的接线方法&#xff0c;并利用DS18B20检测当前温度。 2.所需元器件 F407Micropython开发板…

带你理解Spring AOP

AOP概述 在我们的日常开发中&#xff0c;除了正常业务逻辑外&#xff0c;还可能经常会需要在业务逻辑的特定位置加入日志&#xff0c;以便于调试和问题分析。但是这种插入日志的逻辑和业务逻辑间并不存在连续性和依赖性&#xff0c;这种逻辑侵入随着项目的不断发展&#xff0c…

10.20随笔

ES6 ECMAScript是一种由Ecma国际&#xff08;前身为欧洲计算机制造商协会,英文名称是European Computer Manufacturers Association&#xff09;通过ECMA-262标准化的脚本程序设计语言。 这种语言在万维网上应用广泛&#xff0c;它往往被称为JavaScript或JScript&#xff0c;但…

极客招募令!兄弟杯区块链极客竞技大赛在上海等您来战!

据悉&#xff0c;由国内首家区块链技术社区区块链兄弟主办&#xff0c;旺链科技、离子链、中国云体系产业创新战略联盟、无退社区、指旺金科等单位强力支持&#xff0c;HiBlock区块链社区、火球财经、布洛克财经、海豚区块链、区块网等百家技术社区和媒体通力合作的兄弟杯区块链…