三类基于贪心思想的区间覆盖问题【配套资源详解】

news2024/12/23 1:14:19

博主主页:Yu·仙笙

配套资源:三类基于贪心算法覆盖问题-C++文档类资源-CSDN下载

目录

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

情形1:区间完全覆盖问题

描述:

样例:

解题过程:

例题:

题意:

例题:

例题二:

思路:

情形2:最大不相交区间数问题

例题:

输入格式:

输出格式:

思路:

情形3:区间选点问题。

描述

输入

输出

样例输入

样例输出

练习:POJ 3485 Highway

大意:

Sample Input

Sample Output

思路:


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

情形1:区间完全覆盖问题

描述:

给定一个长度为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],由于7最大,所以下一步选择[3,7],最后一步只能选择[6,8],这个时候刚好达到了8退出,所选区间为3

4贪心证明:

需要最少的线段进行覆盖,那么选取的线段必然要尽量长,而已经覆盖到的区域之前的地方已经无所谓了,(可以理解成所有的可以覆盖的左端点都是已经覆盖到的地方),那么真正能够使得线段更成的是右端点,左端点没有太大的意义,所以选择右端点来覆盖

例题:

Intervals(http://poj.org/problem?id=1089

Description

There is given the series of n closed intervals [ai; bi], where i=1,2,...,n. The sum of those intervals may be represented as a sum of closed pairwise non−intersecting intervals. The task is to find such representation with the minimal number of intervals. The intervals of this representation should be written in the output file in acceding order. We say that the intervals [a; b] and [c; d] are in ascending order if, and only if a <= b < c <= d.

Task

Write a program which:

reads from the std input the description of the series of intervals,

computes pairwise non−intersecting intervals satisfying the conditions given above,

writes the computed intervals in ascending order into std output

Input

In the first line of input there is one integer n, 3 <= n <= 50000. This is the number of intervals. In the (i+1)−st line, 1 <= i <= n, there is a description of the interval [ai; bi] in the form of two integers ai and bi separated by a single space, which are respectively the beginning and the end of the interval,1 <= ai <= bi <= 1000000.

Output

The output should contain descriptions of all computed pairwise non−intersecting intervals. In each line should be written a description of one interval. It should be composed of two integers, separated by a single space, the beginning and the end of the interval respectively. The intervals should be written into the output in ascending order.

Sample Input

5

5 6

1 4

10 10

6 9

8 10

Sample Output

1 4

5 10

题意:

求区间最大覆盖

#include <iostream>

#include <vector>

#include <algorithm>

#include <cstring>

#include <cstdio>

#include <cmath>

using namespace std;

const int maxn=50000+20;

struct area{

int l,r;

}a[maxn];

int cmp(area x,area y){

if(x.l==y.l)return x.r<y.r;

return x.l<y.l;

}

int main(){

int ans,la,lb,n,i;

scanf("%d",&n);

for(i=1;i<=n;i++){

scanf("%d%d",&a[i].l,&a[i].r);

if(a[i].l>a[i].r)swap(a[i].l,a[i].r);

}

sort(a+1,a+n+1,cmp);

la=a[1].l;lb=a[1].r;

for(i=2;i<=n;i++){

if(a[i].l>lb){

printf("%d %d\n",la,lb);

la=a[i].l;lb=a[i].r;

}

else {

lb=max(lb,a[i].r);

}

}

printf("%d %d\n",la,lb);

return 0;

}

例题:

[NOIP2005 普及组] 校门外的树 - 洛谷

#include<bits/stdc++.h>

using namespace std;

const int maxn=100+20;

struct area{

int l,r;

}a[maxn];

int cmp(area x,area y){

if(x.l==y.l)return x.r<y.r;

return x.l<y.l;

}

int main(){

int ans,la,lb,n,i,L;

scanf("%d%d",&L,&n);

for(i=1;i<=n;i++){

scanf("%d%d",&a[i].l,&a[i].r);

if(a[i].l>a[i].r)swap(a[i].l,a[i].r);

}

sort(a+1,a+n+1,cmp);

ans=L+1;la=a[1].l;lb=a[1].r;

for(i=2;i<=n;i++){

if(a[i].l>lb){

ans-=lb-la+1;

la=a[i].l;lb=a[i].r;

}

else {

lb=max(lb,a[i].r);

}

}

ans-=lb-la+1;

cout<<ans<<endl;

return 0;

}

例题二:

思路:

对于输入的每个点,先用勾股定理求出能覆盖住矩形的起点和终点,然后进行一次排序,如果最小的起点和最大的终点都不能超过矩形的长度范围,则必定无解,取出起始点最靠前的点,然后记录下这个点的终点,遍历这个起点到终点范围内的所有其他的点,并挑选其中终点最靠后的那个点作为下一个终点的位置,并且计数器加一,继续向后遍历,如果有区间接不上,则表明无解,成功遍历到矩形最后,则直接输出计数器的值

#include<cstdio>

#include<cstdlib>

#include<iostream>

#include<algorithm>

using namespace std;

const int maxn=10000+10;

struct area{

double l,r;

}a[maxn];

int cmp(area x,area y){

if(x.l==y.l)return x.r<y.r;

else return x.l<y.l;

}

int main(){

int t,n,w,flag,i,tot,x,ans,pos;

double h,tmp,lb,r;

scanf("%d",&t);

while(t--){

scanf("%d%d%lf",&n,&w,&h);

h=h/2;//矩形的高

tot=0;//共tot个矩形覆盖

for(i=1;i<=n;i++){

scanf("%d%lf",&x,&r);

tmp=sqrt(r*r-h*h);//计算矩形的宽

if(tmp>0){

a[++tot].l=max(0.0,x*1.0-tmp);

a[tot].r=x*1.0+tmp;

}

}

sort(a+1,a+tot+1,cmp);

ans=0;

flag=1;

pos=1;

lb=0;//前pos个区间能覆盖的最大区间

for(;lb<w;){

tmp=0;

for(i=pos;a[i].l<=lb&&i<=tot;i++){

tmp=max(tmp,a[i].r);//左边界在lb以内能覆盖到的最远距离

}

if(tmp>lb){

ans++;//增加一个喷头

lb=tmp;//更新lb

pos=i;//更新pos

}

else {//无法往后覆盖

flag=0;

break;

}

}

if(flag)printf("%d\n",ans);else printf("0\n");

}

return 0;

}

情形2:最大不相交区间数问题

数轴上有n个区间[ai,bi],要求选择尽量多个区间,使得这些区间两两没有公共点。

贪心策略:

按照b1<=b2<=b3…的方式排序,然后从前向后遍历,每当遇到可以加入集合的区间,就把它加入集合。(集合代表解的集合)

证明:

我们对a1,a2……的关系分以下几种情况考虑:

1、a1>a2。   此时区间2包含区间1。这种情况下显然不会选择区间2,因为选择区间1会留下更多的剩余空间。

不仅区间2如此,以后所有区间中只要有一个 i 满足a1 > ai,i 都不要选。

即此种情况下,选择区间1是明智的,与策略一致。

2、排除情况1后,一定有a1<=a2<=a3……。

例题:

线段覆盖

已知数轴上0<N<10000条线段。每条线段按照端点Ai和Bi(Ai<>Bi,i=1..N)定义。端点坐标在(-999,999)内,坐标为整数。有些线段可能相交。编程实现删除最少数目的线段,使得余下的任意两条线段不相交。

输入输出格式

输入格式:

第一行为一整数N。接下来有N行,每行包含两个整数 (Ai 和 Bi), 用空格隔开。

输出格式:

整数p,即删除后余下的线段数。

输入输出样例

输入样例#1:

3

6 3

1 3

2 5

输出样例#1:

2

思路:

贪心思想,时间复杂度O(nlog(n))

1. 数据给出个端点可能逆序,需判断处理。

2. 排序,将每一个区间按右端点进行递增顺序排列

3.第一个区间必可保留,记录保留区间的最大右边界为pos,遍历区间i,如果a[i].l>pos,则可保留区间增加,并且pos更新为a[i].r。

#include<bits/stdc++.h>

#define MaxInt 100000

using namespace std;

const int maxn=10000+20;

struct line{

int l,r;

}a[maxn];

int n;

int cmp(line x,line y){return x.r<y.r;}

int main(){

int i;

scanf("%d",&n);

for(i=1;i<=n;i++){

scanf("%d%d",&a[i].l,&a[i].r);

if(a[i].l>a[i].r)swap(a[i].l,a[i].r);

}

sort(a+1,a+n+1,cmp);

int ans=1,pos=a[1].r;

for(i=2;i<=n;i++)

if(a[i].l>=pos){

ans++;

pos=a[i].r;

}

printf("%d",ans);

return 0;

}

情形3:区间选点问题。

数轴上有n个闭区间[ai,bi]。取尽量少的点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个)。

贪心思想:

先按b从小到大进行排序,再选择b0作为选点pos,如果出现ai>pos,则以bi作为pos,再按照这样的方式迭代。直至所有区间遍历完。

描述

上数学课时,老师给了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

#include<cstdio>

#include<cstdlib>

#include<iostream>

#include<algorithm>

using namespace std;

const int maxn=100+10;

struct area{

int l,r;

}a[maxn];

int cmp(area x,area y){

if(x.r==y.r)return x.l<y.l;

else return x.r<y.r;

}

int main(){

int n,i,pos,ans;

while(scanf("%d",&n)!=EOF){

for(i=1;i<=n;i++)

scanf("%d%d",&a[i].l,&a[i].r);

sort(a+1,a+n+1,cmp);

ans=1;pos=a[1].r;

for(i=2;i<=n;i++){

if(a[i].l>pos){

ans++;

pos=a[i].r;

}

}

printf("%d\n",ans);

}

return 0;

}

练习:POJ 3485 Highway

大意:

X轴上公路从0到L,X轴上下有一些点给出坐标代表村庄,问在公路上最少建几个出口才能使每个村庄到出口的距离不超过D。

Sample Input

100

50

3

2 4

50 10

70 30

Sample Output

1

1

思路:

以每个村庄坐标为圆心,D为半径画圆,与X轴有两个交点,得到一个区间,得到N个区间后,就转化为了区间选点问题。策略为:先按区间的右端点从小到大排序,如果相同则按左端点从大到小排序。
 

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <cmath>
#include <algorithm>
using namespace std;
struct point
{
    double left;
    double right;
}po[100000];
int cmp(const void *a,const void *b)
{
    return (*(point*)a).right < (*(point*)b).right ? -1 : 1;
}
int main()
{
    double way_long,dis;
    int n,i,j,k;
    double a,b;
    double rec;
    int re;
    while(scanf("%lf%lf%d",&way_long,&dis,&n)!=EOF)
    {
        re=0;
        for(i=0;i<n;i++)
        {
        scanf("%lf%lf",&a,&b);
        rec=sqrt(dis*dis-b*b);
        po[i].left=a-rec;
        po[i].right=a+rec;
        if(po[i].left < 0)
        po[i].left=0;
        }
        qsort(po,n,sizeof(po[0]),cmp);
       // for(i=0;i<n;i++)
        //printf("%lf\n",po[i].right);
        re=0;
        i=0;
        while(i<n)
        {
            k=i;
            re++;
            while(i<n && po[i].left <= po[k].right) i++;
        }
        printf("%d\n",re);
    }
    return 0;
}

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

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

相关文章

深入理解Kafka服务端之索引文件及mmap内存映射

深入理解Kafka服务端之索引文件及mmap内存映射 - 墨天轮 一、场景分析 Kafka在滚动生成新日志段的时候&#xff0c;除了生成日志文件(.log)&#xff0c;会同时生成一个偏移量索引文件(.index)、一个时间戳索引文件(.timeindex)和一个已中止事务索引文件(.txnindex)。 由于索引写…

JVM面试高频问题

一、进程与线程 在谈JVM的这些问题前&#xff0c;我们先来复习一下有关线程和进程的关系 进程可以看作是程序的执行过程。一个程序的运行需要CPU时间、内存空间、文件以及I/O等资源。操作系统就是以进程为单位来分配这些资源的&#xff0c;所以说进程是分配资源的基本单位。线…

C语言函数章--该如何学习函数?阿斗看了都说会学习了

前言 &#x1f47b;作者&#xff1a;龟龟不断向前 &#x1f47b;简介&#xff1a;宁愿做一只不停跑的慢乌龟&#xff0c;也不想当一只三分钟热度的兔子。 &#x1f47b;专栏&#xff1a;C初阶知识点 &#x1f47b;工具分享&#xff1a; 刷题&#xff1a; 牛客网 leetcode笔记软…

【Python入门指北】 发邮件与正则表达式

文章目录邮件发送一、群发邮件二、指定用户发邮件正则表达式一、预备知识正则1. 正则介绍2. 陷阱3. 特殊的字符二、 re 模块的方法1 常用方法2. 正则分组总结邮件发送 #第三方模块 yagmail #pip3 install yagmailimport yagmail""" 项目需求 yag yagmail.SMTP(u…

MyBatis Plus实现动态字段排序

利用周末时间&#xff0c;对已有的项目进行了升级&#xff0c;原来使用的是tkmybatis&#xff0c;改为mybatis plus。但是由于修改了返回数据的格式&#xff0c;前端页面字段排序失效了&#xff0c;需要刷新表格才会排序。页面效果如下 easyui的数据表格datagrid支持多字段排序…

【仿牛客网笔记】Spring Boot实践,开发社区登录模块-账号设置,检查登录

首先访问账号设置的页面。 新建一个Controller,用过RequestMapping生成访问路径 上传头像 首先打开配置文件&#xff0c;配置一下将文件配置到哪里。 直接在Controller存了&#xff0c; 更新的时候掉Map&#xff0c;参数为id和路径。 注入日志对象后&#xff0c;通过Val…

SpringBoot项目启动执行任务的几种方式

经过整理后得到以下几种常用方式&#xff0c;供大家参考。 1. 使用过滤器 init() &#xff1a;该方法在tomcat容器启动初始化过滤器时被调用&#xff0c;它在 Filter 的整个生命周期只会被调用一次。可以在这个方法中补充想要执行的内容。 Component public class MyFilter …

CTF竞赛网络安全大赛(网鼎杯 )Web|sql注入java反序列化

CTF竞赛网络安全大赛题目考点 sql注入 java反序列化 网鼎杯解题思路 题目一打开是这样的界面 下载题目的附件,并用jd-gui.exe打开 核心代码如下 Test代码 `` package 部分class;import cn.abc.common.bean.ResponseCode; import cn.abc.common.bean.ResponseResult; impor…

持续交付中流水线构建完成后就大功告成了吗?别忘了质量保障

上期文章我结合自己的实践经验&#xff0c;介绍了持续交付中流水线模式的软件构建&#xff0c;以及在构建过程中的3个关键问题。我们可以看出&#xff0c;流水线的软件构建过程相对精简、独立&#xff0c;只做编译 和打包两个动作。 但需要明确的是&#xff0c;在持续交付过程…

网课查题接口使用方法

网课查题接口使用方法 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 查题校园题库&#xff1a;查题校园题库后台&#xff08;点…

Hadoop面试题汇总-20221031

Hadoop面试题汇总 HDFS部分 1、请描述HDFS的写流程。 答&#xff1a; 首先由客户端向 NameNode 发起文件上传请求&#xff0c;NameNode 检查文件要上传的目录&#xff0c;并鉴权。如果上传用户对此目录有权限&#xff0c;则允许客户端进行上传操作。客户端接收到允许指令后&…

本科毕业论文内容必须有国内外文献综述吗?

不知不觉间整个暑假变过去了&#xff0c;现在大部分的大学生都已经开学了。2023届毕业的学生现在也开始借鉴毕业论文的选题工作。但是无论是现在正在选题的大四的同学们还是还在上大一大&#xff0c;二大三的同学们都对毕业论文这4个字有着天生的恐惧感。因为对于大多数人来说&…

阿里为何禁止在对象中使用基本数据类型

大家好&#xff0c;我是一航&#xff01; 前两天&#xff0c;因为一个接口的参数问题&#xff0c;和一位前端工程师产生了一些分歧&#xff0c;需求很简单&#xff1a; 根据一个数值类型&#xff08;type 取值范围1&#xff0c;2&#xff0c;3&#xff09;来查询数据&#xff…

HTML+CSS+JavaScript七夕情人节表白网页【樱花雨3D相册】超好看

这是程序员表白系列中的100款网站表白之一&#xff0c;旨在让任何人都能使用并创建自己的表白网站给心爱的人看。 此波共有100个表白网站&#xff0c;可以任意修改和使用&#xff0c;很多人会希望向心爱的男孩女孩告白&#xff0c;生性腼腆的人即使那个TA站在眼前都不敢向前表白…

pandas 基本数据

目录 1. pandas 简介 2. pandas 基本数据结构 2.1 Series 类型 2.1.1 索引-数据的行标签 2.1.2 值 2.1.3 切片 2.1.4 索引赋值 2.2 DataFrame 类型 1. pandas 简介 一般导入的形式&#xff1a;import pandas as pd 2. pandas 基本数据结构 python 的数据结构&#xff1a…

python爬虫之Scrapy框架,基本介绍使用以及用框架下载图片案例

一、Scrapy框架简介 Scrapy是:由Python语言开发的一个快速、高层次的屏幕抓取和web抓取框架&#xff0c;用于抓取web站点并从页面中提取结构化的数据&#xff0c;只需要实现少量的代码&#xff0c;就能够快速的抓取。 Scrapy使用了Twisted异步网络框架来处理网络通信&#xf…

Servlet篇 —— 我的第一个Servlet程序

☕导航小助手☕ &#x1f35a;写在前面 &#x1f35c;一、Maven的介绍 &#x1f371;​二、第一个Servlet的创建 &#x1f354;&#x1f354;2.1 创建项目 &#x1f969;&#x1f969;​2.2 引入依赖 &#x1f9aa;&#x1f9aa;​2.3 创建目录 &#x1f363;&#x1f363;2.4…

没想到GoFrame的gcache天然支持缓存淘汰策略

gcache提供统一的缓存管理模块&#xff0c;提供了开发者可自定义灵活接入的缓存适配接口&#xff0c;并默认提供了高速内存缓存适配实现。 先说结论 这篇文章通过结合商业项目的使用场景&#xff0c;为大家介绍了gcache的基本使用、缓存控制以及淘汰策略。 使用gcache做缓存处…

3分钟,快速上手Postman接口测试

Postman是一个用于调试HTTP请求的工具&#xff0c;它提供了友好的界面帮助分析、构造HTTP请求&#xff0c;并分析响应数据。实际工作中&#xff0c;开发和测试基本上都有使用Postman来进行接口调试工作。有一些其他流程的工具&#xff0c;也是模仿的Postman的风格进行接口测试工…

推荐 4 个开源工具

Hi&#xff0c;艾瑞巴蒂&#xff0c;晚上好&#xff01;今天推荐 4 个登上 GitHub 热搜的开源项目&#xff0c;它们分别是&#xff1a;1. 炫酷的 UI 工具&#xff1a;glslViewer2. Textual3. ToolJet&#xff1a;开源的低代码开发框架4. Linux 命令大全搜索工具01炫酷的 UI 工…