一、区间完全覆盖问题

问题描述:给定一个长度为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

三类基于贪心思想的区间覆盖问题相关推荐

  1. Algorithm:贪心策略之区间覆盖问题

    Describe: 给定一个大区间1-T,以及n个小区间,要求用最少个数的小区间来覆盖大区间: Input: 第一行,输入n和T: 随后n行输入对应区间的起始终止坐标 Output: 输出覆盖区间1- ...

  2. NYOJ 6 喷水装置(一) 贪心算法 之 区间覆盖问题

    喷水装置(一) 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 现有一块草坪,长为20米,宽为2米,要在横中心线上放置半径为Ri的喷水装置,每个喷水装置的效果都会让以它为 ...

  3. 区间覆盖全部类型及部分精选习题汇总详解(贪心策略)

    内容如下: 1)区间完全覆盖问题 问题描述:给定一个长度为m的区间,再给出n条线段的起点和终点(注意这里是闭区间),求最少使用多少条线段可以将整个区间完全覆盖 样例: 区间长度8,可选的覆盖线段[2, ...

  4. 高效算法——E - 贪心-- 区间覆盖

    E - 贪心-- 区间覆盖 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=85904#problem/E 解题思路: 贪心思想, ...

  5. sdut 2074 区间覆盖问题(贪心)

    区间覆盖问题 Time Limit: 1000MS Memory limit: 65536K 题目描述 用i来表示x坐标轴上坐标为[i-1,i]的长度为1的区间,并给出n(1≤M≤200)个不同的整数 ...

  6. 贪心法——区间覆盖问题

    贪心法--区间覆盖问题 区间覆盖问题.数轴上有n个闭区间[ai,bi][a_i, b_i],选择尽量少的区间覆盖一条指定线段[s,t][s,t]. 先进行预处理,将不包含[s,t][s,t]的区间都去 ...

  7. 贪心 区间覆盖最小值

    贪心 区间覆盖最小值 POJ 2376 大概题意: 从1到T区间内,必须保证每个点都有牛在工作,给出每头牛的工作时间,求需用到的最小的牛的数量,无解输出-1 一开始以为组合[1,4] [5,T]不算覆 ...

  8. 【算法笔记】:区间覆盖问题:贪心算法

    证明贪心算法的正确性: 下面证明: (1)最优子结构: 假设结果有n个区间,去掉最后一个区间及对应的点,则前n-1个区间仍然是覆盖所有点的所用的最少区间(最优解的子结构是子问题的最优解) 证明: cu ...

  9. 10382 - Watering Grass(贪心 区间覆盖问题)洒水面覆盖

    double qiuzhi(int id) {double t1=cc[id].rid*cc[id].rid;double t2=w*w/4;double t3=t1-t2;double t4=sqr ...

最新文章

  1. 装管家婆系统要开启那些服务器,管家婆服务器维护注意的一些事项?
  2. 组网中交换机虚拟化技术的应用
  3. flash 绘图API:绘制基础的图形
  4. 得到当前函数堆栈调用
  5. Java Script 第十节课 Java Script的for循环练习。
  6. 设计模式之观察者模式demo
  7. 【Ynoi2011】成都七中【树论】【点分树】【离线】【树状数组】
  8. 【TypeScript系列教程04】编译参数
  9. Ubuntu 配置 Tomcat
  10. 面试指南(二):想跳槽,这些技术点你会了吗?
  11. 测试~在使用共通处理时,需要注意的问题 ~ 使用前,清空Form中的值。
  12. Python Django 个人博客源码(附个人源码和网站参考)
  13. Redis 入门指南
  14. 英文论文要怎么查重?
  15. CBR,VBR,ABR,CQP四种编码方式。
  16. 聊一聊,android程序员前景如何
  17. 【税务硕士论文】跨国公司无形资产转让定价税制改革探究(节选)
  18. 【Cython】Cython 基本用法
  19. 从多个Word文档中批量取值,整理到Excel表中。
  20. 编译原理: Subset Construction 子集构造法(幂集构造)(NFA转DFA)

热门文章

  1. python选择表单_如何使用Python在表单中选择选项?
  2. 【NC54 三数之和】(待整理)
  3. 【NC30】缺失的第一个正整数
  4. 【牛客 - 330G】Applese 的毒气炸弹(最小生成树,构造,判连通图)
  5. *【HDU - 2819】Swap(二分图匹配,输出路径)(待证明:是否是最少交换次数?)
  6. *【CodeForces - 574A】Bear and Elections (优先队列,水题模拟)
  7. 【动态规划模型】金矿模型理解动态规划!(精彩的故事)
  8. python 问题集
  9. 使用PDF.js实现前端和手机端网页预览PDF文件(可定制,支持本地文件、Base64编码和远程URL跨域方式)
  10. Scaffold php,GitHub - yiiplus/scaffold: scaffold是一个基于Yii2高级项目模版工程化实现的应用程序...