当前位置:首页 > 算法 > 正文内容

【贪心】区间覆盖

亿万年的星光4年前 (2021-02-02)算法1749

【题目描述】

给定一个长度为m的区间,再给出n条线段的起点和终点(本题考虑闭区间),求最少使用多少线段可以将整个区间完全覆盖。

【输入】

第一行是区间长度m。第二行是n,表示有n个可选区间。后面跟着n行数据,每行包含两个值,第一个是当前区间的起始端点值,第二个是当前区间的结束端点值。

【输出】

能覆盖m的最少的区间个数

【输入样例1】

C++
8
6
2 6
1 4
3 6
3 7
6 8
2 4
3 5

【输出样例1】

C++
3


【举例】

20220226.png

例如:M=5,整数1、3、4、8、11表示区间。
    要求:所用线段不超过 N=3条。


【问题描述】
给定n个区间和一个范围[a, b],选择尽量少的区间,使得[a, b]能够被完全覆盖。


【题目分析】

注意题目要求是要用“线段”覆盖“区间”。如果有一个线段足够长,可以直接覆盖整个区间,那么一定就选它,否则就要选择尽可能少的“线段”来覆盖掉整个“区间”。

【贪心策略】

BASIC
对于当前区间[a,b]来说,选择的下一个区间的左端点值a2一定不会大于b,否则就不能完成“覆盖”这一操作。
对于当前区间[a,b]来说,如果有多个区间都满足条件1,那么一定选择右端点最大的区间,否则就不能满足“最小”这一目的。

【思路】

BASIC
将所有的区间按左端点从小到大排序,依次处理每个区间。每次选择覆盖点s的区间右端点坐标中最大的一个。并将更新为该区间的右端点坐标,直到选择的区间已经包含了t为止。
贪心策略:在某个时刻的s。找一个满足 a[i]<<s的b[i]最大值即可。


【贪心策略及证明】

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

方法:

  • (1)先将n个区间按照起点进行递增排序。

  • (2)令s表示已经覆盖到的区域。再剩下的区间中找出所有左端点小于等于当前已经覆盖到的区域s并且右端点大于等于s的区间,取右端点最大的区间加入,直到已经覆盖全部的区域。

【求解过程】

  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的区间。

【伪代码】

C++
while(剩余区间数目不为0)
{
	if(总长度已经超出覆盖范围) {
		结束循环; 
	} 
	for(循环查找符合条件的下一个最大区间)
	if(找到了){
		答案数+1;
		总长度+=最大能切换的区间长度 
	}else{
		表示不能完全覆盖, 退出循环 ,答案数=0 
	}
}

【例题】

【题目描述】

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

【输入描述】

第一行输入一个正整数N表示共有n次测试数据。 

每一组测试数据的第一行有三个整数n,w,h,n表示共有n个喷水装置,w表示草坪的横向长度,h表示草坪的纵向长度。 

随后的n行,都有两个整数xi和ri,xi表示第i个喷水装置的的横坐标(最左边为0),ri表示该喷水装置能覆盖的圆的半径。

【输出描述】

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

【样例输入】

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

【样例输出】

BASIC
1 
2

【参考代码】

C++
 

 
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
 
#define INF 1e-6    //双精度浮点数趋近于0的值
#define MAX 10005
 
struct Node {
    double left;
    double right;
} map[MAX];
 
int num_input = 0;
int length = 0;
int width = 0;
 
int cmp(Node a,Node b)
{
    if(a.left !=  b.left) { //这里按左端点排序比较方便
        return a.left < b.left;
    }
 
    return a.right < b.right;
}
 
double calue(int r)
{
    double res;
    res = (double)r*r - (double)width*width/4.0;
 
    if(res >= INF) {
        res = sqrt(res);
    } else {
        res = 0;
    }
 
    return res;
}
 
int main()
{
    int time = 0;
    scanf("%d", &time);
    while(time--) {
        scanf("%d%d%d", &num_input, &length, &width);
 
        int a = 0;
        int b = 0;
        double res = 0;
        for(int i = 0; i < num_input; i++) {
            scanf("%d %d",  &a, &b);
            res = calue(b);
            map[i].left = a - res;
            map[i].right = a + res;
        }
 
        sort(map, map+num_input, cmp);
 
        double sum = 0;
        int ans = 0;
        while(sum < length) {
            double num_max = 0;
            for(int i = 0; i < num_input && map[i].left <= sum; i++) {
                num_max = max(num_max, map[i].right-sum);
            }
 
            if(0 == num_max) {
                ans = 0;
                break;
            } else {
                sum += num_max;
                ans++;
            }
        }
 
          printf("%d\n",ans);
    }
    return 0;
}
阅读剩余的73%

扫描二维码推送至手机访问。

版权声明:本文由青少年编程知识记录发布,如需转载请注明出处。

相关文章

【算法】高精度(1)

一、  什么是高精度高精度算法,属于处理大数字的数学计算方法。在一般的科学计算中,会经常算到小数点后几百位或者更多,当然也可能是几千亿几百亿的大数字。一般这类数字我们统称为高精度数,高精度算...

【贪心】----基本概念

一、基本概念所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,它所做出的仅仅是在某种意义上的局部最优解。贪心算法没有固定的算法框架,算法设计的关键是贪...

【贪心】 导弹拦截

【贪心】 导弹拦截

【题目描述】某国为了防御敌国的导弹袭击,开发出一种导弹拦截系统,但是这种拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来...

【算法】高精度(2)

五、高精度处理进位与借位    其实也很简单,我们再来模拟一下,1439+887的时候,首先我们最低位相加,得到16,那么答案最低位就是6,再进个1,然后两数的十位相加,...

【算法】最短路径算法——Floyed-Warshell算法

【算法】最短路径算法——Floyed-Warshell算法

如下图所示,我们把边带有权值的图称为带权图。边的权值可以理解为两点之间的距离。一张图中任意两点间会有不同的路径相怜。最短路径就是指连接两点的这些路径中最短的一条。【注意】边的权值可以为负。当出现负边权...

【算法】动态规划(三)——解题方法与解题思路

0.前言动态规划最核心的思想就是:拆分子问题,记住过往,减少重复计算。动态规划可以从下面的参考网上的一个例子:A :"1+1+1+1+1+1+1+1 =?"...