蓝桥杯算法精讲:贪心算法之区间问题深度剖析

目录

  • 前言
  • 一、贪心算法
    • [1.1 区间问题](#1.1 区间问题)
      • [1.1.1 线段覆盖](#1.1.1 线段覆盖)
      • [1.1.2 Radar Installation](#1.1.2 Radar Installation)
      • [1.1.3 Sunscreen](#1.1.3 Sunscreen)
      • [1.1.4 牛栏预定](#1.1.4 牛栏预定)
  • 结语

🎬 云泽Q个人主页
🔥 专栏传送入口 : 《C语言》《数据结构》《C++》《Linux》《蓝桥杯系列

⛺️遇见安然遇见你,不负代码不负卿~


前言

大家好啊,我是云泽Q,欢迎阅读我的文章,一名热爱计算机技术的在校大学生,喜欢在课余时间做一些计算机技术的总结性文章,希望我的文章能为你解答困惑~

一、贪心算法

1.1 区间问题

区间问题是另一种比较经典的贪心问题。题目面对的对象是一个一个的区间,让我们在每个区间上做出取舍。

这种题目的解决方式一般就是按照区间的左端点或者是右端点排序,然后在排序之后的区间上,根据题目要求,制定出相应的贪心策略,进而得到最优解。

具体是根据左端点还是右端点排序?升序还是降序?一般是假设一种排序方式,并且制定贪心策略,当没有明显的反例时,就可以尝试去写代码。

1.1.1 线段覆盖

凌乱的yyy / 线段覆盖


解法

按照区间左端点从小到大排序,当两个区间「重叠」的时候,我们必须要舍弃一个。为了能够「在移除某个区间后,保留更多的区间」,我们应该把「区间范围较大」的区间移除。

因此以第一个区间为基准,遍历所有的区间:

  • 如果重叠,选择「最小的右端点」作为新的基准;
  • 如果不重叠,那么我们就能多选一个区间,以「新区间为基准」继续向后遍历。
cpp 复制代码
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long LL;
const int N = 1e6 + 10;
struct node{
	LL l;
	LL r;
}a[N];
LL n;

bool cmp(node& x, node& y)
{
	return x.l < y.l;
}

int main()
{
	cin >> n;
	for(int i = 1; i <= n; i++) cin >> a[i].l >> a[i].r;
	sort(a + 1, a + 1 + n, cmp);
	//以第一个区间为右端点,第一个区间必选
	LL ret = 1;
	//以第一个区间的右端点为基准向后选择
	LL right_side = a[1].r;
	for(int i = 2; i <= n; i++)
	{
		LL left = a[i].l, right = a[i].r;
		//重叠 
		if(left < right_side)
		{
			//保留右端点较小的区间
			right_side = min(right_side, right);
		}else{//不重叠 
			ret++;
			right_side = right;
		}
	}
	cout << ret << endl;
	return 0;
}


1.1.2 Radar Installation

Radar Installation

如图所示,当一个岛屿的坐标已知,其实可以计算出:当雷达放在 x 轴的哪段区间时,可以覆盖到这个岛屿

根据勾股定理得:ax的长度 l=根号下d2−y2,那么雷达所处的范围就是 [x - l,x + l]。因此,针对每一个岛屿,我们都可以算出一个能够覆盖它的区间。

原问题就变成给定一些区间,从中选取一些区间(尽量多的重叠区间),能够覆盖掉所有的岛屿,最少能够选多少个。就从二维平面转化成一维线段

cpp 复制代码
#include<iostream>
#include<cmath>      //开根号用 
#include<algorithm>  //sqort
using namespace std;

//区间数/岛屿数 
const int N = 1010;
double d;
int n;

//存储每个岛屿对应的「雷达可覆盖区间」(x轴上的区间)
struct node{
	//计算的时候因为涉及开根号,所以这里的数据类型是double
    double l;
    double r;
}a[N];

// 排序比较函数:按区间左端点升序排序
bool cmp(node& x, node& y)
{
    return x.l < y.l;
}

int main()
{
    int cnt = 0;  // 记录测试用例的编号(Case 1、Case 2...)
    while(cin >> n >> d, n && d)
    {
        cnt++;
        //标记是否存在无法覆盖的岛屿(y > d)
        bool flag = false;
        
        // 遍历所有岛屿,计算每个岛屿对应的雷达覆盖区间
        for(int i = 1; i <= n; i++)
        {
            double x, y; cin >> x >> y;
            //岛屿的y坐标超过雷达半径,垂直距离已超范围,无法覆盖
            if(y > d) flag = true;
            // 勾股定理
            double l = sqrt(d * d - y * y);
            //计算该岛屿对应的雷达覆盖区间:[x-l, x+l]
            a[i].l = x - l;
            a[i].r = x + l;
        }

        cout << "Case " << cnt << ": ";
        // 如果存在无法覆盖的岛屿,直接输出-1
        if(flag) cout << -1 << endl;
        else{
            sort(a + 1, a + 1 + n, cmp);
            //最少雷达数,初始为1(至少需要1个雷达覆盖第一个区间)
            int ret = 1;  
            //用第一个区间右端点作为基准,判断第二个区间是否与其重叠
            double r = a[1].r;
            
            for(int i = 2; i <= n; i++)
            {
                double left = a[i].l;
                double right = a[i].r;
                
                //情况1:当前区间与已覆盖区域重叠(能被当前雷达覆盖)
                if(left <= r)
                {
                    //只有取更小的右端点,才能同时覆盖重叠的所有区间
                    r = min(r, right);
                }
                //请况2:当前区间与已覆盖区域不重叠,需要新增雷达
                else{
                    ret++;
                    //新雷达的最优位置为当前区间的右端点
                    r = right;      
                }
            }
            cout << ret << endl;
        }
    }
    return 0;
}

要点补充:
为什么把所有区间按左端点 l 从小到大排序。

这样我们可以从左到右处理区间,保证每次处理的都是当前最靠左的区间,不会漏掉任何需要覆盖的区域。

while (cin >> n >> d, n && d)如果括号内有一个逗号隔开的话,就是一个逗号表达式,其会从左向右执行,前面cin >> n >> d执行完后,当n和d不为0的时候才会继续执行下一步,二者为0时while循环跳出

1.1.3 Sunscreen

1.1.4 牛栏预定


结语

相关推荐
wuweijianlove30 分钟前
算法复杂度估算的实验建模与可视化表达的技术6
算法
执笔画流年呀31 分钟前
7大排序算法
java·算法·排序算法
AI成长日志37 分钟前
【算法学习专栏】动态规划基础·中等两题精讲(198.打家劫舍、322.零钱兑换)
学习·算法·动态规划
计算机安禾39 分钟前
【数据结构与算法】第28篇:平衡二叉树(AVL树)
开发语言·数据结构·数据库·线性代数·算法·矩阵·visual studio
测试_AI_一辰40 分钟前
AI 如何参与 Playwright 自动化维护:一次自动修复闭环实践
人工智能·算法·ai·自动化·ai编程
未来之窗软件服务1 小时前
算法设计—计算机等级考试—软件设计师考前备忘录—东方仙盟
算法·软件设计师·计算机等级考试
未来之窗软件服务1 小时前
哈夫曼树构造—计算机等级考试—软件设计师考前备忘录—东方仙盟
算法·软件设计师·计算机等级考试·仙盟创梦ide·东方仙盟
SUNNY_SHUN2 小时前
VLM走进农田:AgriChat覆盖3000+作物品类,607K农业视觉问答基准开源
论文阅读·人工智能·算法·开源
黎阳之光2 小时前
视频孪生赋能车路云一体化,领跑智慧高速新征程
人工智能·算法·安全·数字孪生
Darkwanderor2 小时前
高精度计算——基础模板整理
c++·算法·高精度计算