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

【贪心】区间覆盖

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

【题目描述】

给定一个长度为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%

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

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

相关文章

【二分】----基础用法

【二分】----基础用法

0.二分法简介二分法是一种查找算法要求:数据必须是有序序列核心思想:掐头去尾取中间1. 引入对于一个有序数组,如{1,3,6,8,23,56,78,99},如果我们要查找其中的一个数78的下标位置,按...

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

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

【算法】二叉树(1):二叉树及其编号

【算法】二叉树(1):二叉树及其编号

0.前言        二叉树(Binary Tree)的递归定义如下:二叉树要么为空,要么由根结点(root)、左子树(left...

【算法】滑动窗口1—窗口大小固定

【算法】滑动窗口1—窗口大小固定

一、定义滑动窗口算法(Sliding Window Algorithm)是一种用于解决数组或字符串中子数组或子串问题的优化技术。它通过维护一个窗口(通常是数组或字符串的一个连续子区间),在遍历过程中动...

【算法】归并排序

【算法】归并排序

一、基本思想归并排序的核心思想是将两个已经有序的子序列合并成一个有序序列。整个过程分为两个主要步骤: 1.分解:将待排序的序列不断二分,直到每个子序列只包含一个元素(此时自然有序) ...

【算法】最小重量机器设计

【题目描述】设某一机器由n个部件组成,每一种部件都可以从m个不同的供应商处购得。设Wij 是 从供应商j处购得的部件i的重量,Cij 是相应的价格。 试设计一个算法,给出总价格不超...