区间贪心

news2024/11/15 15:48:29

目录

1.贪心算法的思想

2.区间贪心算法常用的一些题目类型

1.选择最多不相交区间问题

P2970 [USACO09DEC] Selfish Grazing S

 1.思路分析

2.上代码

2.区间选点问题

P1250 种树

1.题目

2.方法一

1.代码解释

 3.方法二

3.区间合并问题

P2434 [SDOI2005] 区间

1. 思路分析

2.上代码

4.区间覆盖问题

 P1668 [USACO04DEC] Cleaning Shifts S

1.思路分析

 2.代码解释

5.区间分组

T471772 cici排课

​编辑 1.一点点思路

2.代码实现与算法思路

3.举一反三

3.遇到了(区间)贪心的题我们应该怎么做

end👍🏻⭐ok?


1.贪心算法的思想

贪心算法是从问题的初始状态出发,通过若干次的贪心选择而得到的最优值(或较优值)的1种求解问题策略,即贪心策略。

2.区间贪心算法常用的一些题目类型

1.选择最多不相交区间问题

P2970 [USACO09DEC] Selfish Grazing S

洛谷:P2970 [USACO09DEC] Selfish Grazing S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P2970

 1.思路分析

题题目的大概意思就是给定我们N个区间,求最多不相交区间有多少个。

我们可以按照区间的右端点从小到大排序

 然后我们创建一个变量命名为j和一个变量cnt(计数),再次循环整个结构体(输入的那些区间,已经排序完), 如果循环到的这个区间的左端点在标签变量j的右边,把j更新为这个区间的左端点,cnt++

2.上代码
#include <bits/stdc++.h>
using namespace std;
struct M{
    int s,e;
}a[500005];
bool cmp(M x,M y){
    return x.e <y.e;
}
int main(){
    int n;
    cin >> n;
    for(int i =0; i < n; i++){
        cin >> a[i].s >> a[i].e;
    }
    sort(a,a+n,cmp);
    int j = -1,cnt = 0;
    for (int i =0; i < n; i++){
        if (a[i].s >= j){
            j = a[i].e;
            cnt ++;
        }
    }
    cout << cnt;
    return 0;
}

2.区间选点问题

P1250 种树

洛谷:

P1250 种树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P1250

1.题目

 

2.方法一

 把所有树都往右边种,为了让他们重叠区间的更多,而且重叠的部分大部分都在右侧,我们就要让这些区间按右端点,从小到大排序,下图是我列举的样例。

首先先把样例归一整一下(排序)

123456789
||
|
|

从第一个开始在尾巴上种树,如果这个区间内已经种到了t[i]棵的话就不种了 , 如果没有种到这么多棵树那就得从后往前,循环种树只要种到为止.(括号代表已经种上树了,+1代表多种一棵树)

123456789
|(|)+1(】)+1
(【)(|)(】)被底下的人种上了
(【)(|)+1
(【)+1(】)+1

其实这样的话更形象,就是有点乱:

123456789
([)|(|[)(]|[)(]|)]([)(])

 同样颜色是一个区间

贪心加模拟的思想

1.代码解释
#include <bits/stdc++.h>
using namespace std;
bool v[100005];
struct Sa{
    int a,b,c;
}s[100005];
bool cmp(Sa x,Sa y){
    return x.b < y.b;
}

我定义了一个叫做s的 结构体,s[i].a = b,s[i].b = e,s[i].c = t(这些值和题目中的数);

这一段代码靠下的cmp是排序函数

v数组就是大街,就是那个有点乱的图

___________________________优雅的分界线_______________________

输入+排序 

int main(){
	int q;
    int n;
	cin >> q>> n;
    for (int i =1; i <= n; i++){
        cin >> s[i].a >> s[i].b >> s[i].c;
    }
    sort(s+1,s+n+1,cmp);

___________________________优雅的分界线_______________________

    int cnt = 0;
    for (int i = 1; i <= n; i++){
    	int sum = 0;
    	for (int j = s[i].a; j <= s[i].b; j++){
    		if (v[j]) sum ++;
		}
		if (sum >= s[i].c){
			continue;
		}

 循环的第一部分, sum的值是在这个区间内种了多少棵树,如果已经种够了那就不用循环这一次看下一次区间.

___________________________优雅的分界线_______________________

		sum = s[i].c - sum;
		cnt += sum;
    	for (int j = s[i].b; j >= s[i].a; j--){
    		if (v[j] == 0){
    			sum --;
    			v[j] = 1;
    			
			}
			if (sum == 0){
				break;
			}
		}

 循环的第二部分,sum值变成还差多少棵树,总共棵数增加sum,循环种树(倒过来循环);

___________________________优雅的分界线_______________________

最后输出cnt;

___________________________优雅的分界线_______________________

总体代码

#include <bits/stdc++.h>
using namespace std;
bool v[100005];
struct Sa{
    int a,b,c;
}s[100005];
bool cmp(Sa x,Sa y){
    return x.b < y.b;
}
int main(){
	int q;
    int n;
	cin >> q>> n;
    for (int i =1; i <= n; i++){
        cin >> s[i].a >> s[i].b >> s[i].c;
    }
    sort(s+1,s+n+1,cmp);
    int cnt = 0;
    for (int i = 1; i <= n; i++){
    	int sum = 0;
    	for (int j = s[i].a; j <= s[i].b; j++){
    		if (v[j]) sum ++;
		}
		if (sum >= s[i].c){
			continue;
		}
		sum = s[i].c - sum;
		cnt += sum;
    	for (int j = s[i].b; j >= s[i].a; j--){
    		if (v[j] == 0){
    			sum --;
    			v[j] = 1;
    			
			}
			if (sum == 0){
				break;
			}
		}
	}
	cout << cnt;
    return 0;
}
 3.方法二

换1种方法可以反过来运算,就像加有减,除有乘

也就是从左到右去种树,排序的时候按照左端点从小到大排序,

直接演示代码吧!

#include <bits/stdc++.h>
using namespace std;
bool v[100005];
struct Sa{
    int a,b,c;
}s[100005];
bool cmp(Sa x,Sa y){
    return x.a > y.a;
}
int main(){
	int q;
    int n;
	cin >> q>> n;
    for (int i =1; i <= n; i++){
        cin >> s[i].a >> s[i].b >> s[i].c;
    }
    sort(s+1,s+n+1,cmp);
    int cnt = 0;
    for (int i = 1; i <= n; i++){
    	int sum = 0;
    	for (int j = s[i].a; j <= s[i].b; j++){
    		if (v[j]) sum ++;
		}
		if (sum >= s[i].c){
			continue;
		}
		sum = s[i].c - sum;
		cnt += sum;
    	for (int j = s[i].a; j <= s[i].b; j++){
    		if (v[j] == 0){
    			sum --;
    			v[j] = 1;
    			
			}
			if (sum == 0){
				break;
			}
		}
	}
	cout << cnt;
    return 0;
}

3.区间合并问题

P2434 [SDOI2005] 区间

网址:

P2434 [SDOI2005] 区间 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P2434

 

1. 思路分析

给出若干个区间让我们输出它们可以合并出来最少的区间(个数,但是输出区间)。

1.按照左端点排序

2.排序完了以后定义两个变量L和R,L=第一个区间的左端点,R=第一个区间的右端点

3.遍历一遍这些区间(不包含第一个)

4.如果这个区间的左端点(开端),大于了R(这个区间不在我们L~R里不包含它),输出L和R,把L的值更新为这个区间的左端点(更新一下整个区间)

5. R的值和区间的右端点做比较选取最大的那个值更新R

2.上代码
#include <bits/stdc++.h>
using namespace std;
struct B{
    int l,r;
}a[1000005];
bool cmp(B x, B y){
    return x.l < y.l;
}
int main(){
    int n;
    cin >> n;
    for (int i = 0; i < n; i++){
        cin >> a[i].l >> a[i].r;
    }
    sort(a,a+n,cmp);
    int R = a[0].r,L = a[0].l;
    for (int i=1; i <n ; i++){
        if (a[i].l > R){
            cout << L << " " << R << "\n";
            L = a[i].l;
        }
            R = max(a[i].r,R);
    }
    cout << L << " " << R << "\n";
    return 0;
}

4.区间覆盖问题

 P1668 [USACO04DEC] Cleaning Shifts S

 P1668 [USACO04DEC] Cleaning Shifts S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P1668

这道题题目的意思是:给定我们一个区间1~T,我们有N个小区间,请问需要最少几个小区间可以覆盖整个大区间(1~T),请注意两个区间之间可以差一,只要每个时间段都有奶牛也可以,比如(1,2)(3,4)它们就可以并到一起去。虽然它讲起来是时间段但是它做起来是时间点。

1.思路分析

图片分析请看下图

 2.代码解释
#include <bits/stdc++.h>
using namespace std;
struct Sa{
    int a,b;
}s[100005];
bool cmp(Sa x,Sa y){
    return x.a < y.a;
}
int main(){
    int n,t;
    cin >> n >> t;
    int cnt=0;
    for (int i= 1; i <= n; i++){
        cin >> s[i].a >> s[i].b;
        
    }
    sort(s+1,s+n+1,cmp);

结构体函数+排序函数cmp按照左端点从小到大排+输入与排序

int l = 1,r = -1;
    for (int i = 1; i <= n;){
        if (s[i].a > l){
            cout <<-1;
            return 0;
        }

如果左端点最靠前的那个区间,左端点还是大于L,说明整个区间结构体没有一个左端点小于等于L,输出负一不能实现


        while (i <= n and s[i].a <= l){
            r = max(s[i].b,r);
            i++;
        }
        cnt ++;

去看,左端点小于等于,而且右端点是最大的.增加区间段数(cnt).


        if (r >= t){
            cout << cnt;
            return 0;
        }
        l = r +1;
    }

如果我们的最大值已经超过了T输出cnt,把L更新为r+1.

cout << -1;
    return 0;
}

对如果在循环里都没结束的话,说明不可以实现输出-1

 总体代码

#include <bits/stdc++.h>
using namespace std;
struct Sa{
    int a,b;
}s[100005];
bool cmp(Sa x,Sa y){
    return x.a < y.a;
}
int main(){
    int n,t;
    cin >> n >> t;
    int cnt=0;
    for (int i= 1; i <= n; i++){
        cin >> s[i].a >> s[i].b;
        
    }
    sort(s+1,s+n+1,cmp);
    int l = 1,r = -1;
    for (int i = 1; i <= n;){
        if (s[i].a > l){
            cout <<-1;
            return 0;
        }
        while (i <= n and s[i].a <= l){
            r = max(s[i].b,r);
            i++;
        }
        cnt ++;
        if (r >= t){
            cout << cnt;
            return 0;
        }
        l = r +1;
    }
    cout << -1;
    return 0;
}

5.区间分组

呃……,这道题你们就看图片吧!

T471772 cici排课

 1.一点点思路

这个题目不在于老师的编号是多少哪个老师该上哪节课,只用求出老师的个数就行。

只要有课程下课了的话我们就可以释放老师,如果释放了新课,既要把新课排给被释放的老师.

2.代码实现与算法思路

#思路

我们输给两个数组(a,b),注意在这里不要用区间的眼光看这两个数组, 数组要分开来排序, a从小到大排序b也从小到大排序,定义一个变量cnt(老师数量)然后循环:

a的i号位的数与b的第j号位对比,如果小于等于B的第j号位{

        cnt++

        查看a的i+1号位//也就是i++;

}//这个循环也就是循环到a[i]>b[j],看一看在b[j]这个课结束之前,还会上多少节课

如果b[j]比a[i]为小的话{//也就是说有老师被释放出来了

        cnt --

        j++;//看下一位

}

#代码实现,增加一些判断我会进行注释 

为什么要求最大值,因为这种方法是最值的,而求最大值是要求这种最值方法需要多少名老师

#include <bits/stdc++.h>
using namespace std;
int a[100005],b[100005];
int main(){
    int n;
    cin >> n;
    for (int i =0; i < n; i++){
        cin >> a[i] >> b[i];
    }
    sort(a,a+n);
    sort(b,b+n);
    int i = 0,j = 0,big = -1,cnt = 0;
    while (1){
        while (i < n and a[i] <= b[j]){
            cnt ++;
            big = max(cnt,big);//求最大值
            i ++;
        }
        if (i >= n) break;  //如果要上的课都检查完了就退出输出最大值
        while (j < n and b[j] < a[i]){
            cnt --;
            j ++;
        }
    }
    cout << big;
    return 0;
}
3.举一反三

这道题会让我们想起“匹配括号”,虽然不知道这个题名字叫做什么,但是题目的大致意思如下:

输入一个字符串字符串用“(”和“)”组成,“(”和“)”可以形成一组,请问输入的字符串有没有多余的括号。如果没有输出“yes”如果有输出“no”(不加引号)。

就比如输入:

((())())

很明显是匹配上了的

请看下列表格是我们这道题的算法,左括号加一,右括号减一

12321210

如果最后等于零的话就可以匹配成功.

不过你可能会问这道题和cici排课有什么关系 ,你可以把题目改编一下变成:

还是输入一个字符串,每一个符号(左括号、右括号)之间,输出我们的cnt最大值。

我们借鉴上面的表格,这个题目就可以输出3

而我们的CiCi排课也是同样的道理,左括号是开始上课,右括号是结束上课,问你老师人数的最大值.

3.遇到了(区间)贪心的题我们应该怎么做

找出我们要排序的顺序按什么排序,

再进行循环,加入题目的要求

最后说一句特殊题目特殊判断,一定要变得灵活起来.

end👍🏻⭐

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

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

相关文章

容器docker

文章目录 前言一、docker1.1 为什么有docker1.2 docker架构1.3 docker 安装1.4 docker中央仓库1.5 docker 基本指令1.6 docker数据卷&#xff0c;挂载例&#xff1a;nginx 数据卷挂载例&#xff1a;mysql 本地持久化 1.7 镜像制作镜像结构dockerfile基础指令容器生成镜像 1.8 d…

JFlash读取和烧录加密stm32程序

JFlash读取和烧录加密stm32程序 安装后JFlash所在的目录&#xff1a;C:\Program Files\SEGGER\JLink 一、烧写加密程序 1、打开C:\Program Files\SEGGER\JLink目录&#xff0c;找到JFlash.exe,双击它&#xff0c;就可以打开该执行程序。见下图&#xff1a; 2、选择“Create …

Vue基础知识:Vue3.3出现的defineOptions,如何使用,解决了什么问题?

1.那么为什么会出现defineOptions? 原因说明&#xff1a; 有<script setup></script>语法糖应用之前&#xff0c;如果要定义 props&#xff0c;emits 可以轻而易举地添加一个与 setup 平级的属性。但是用了<script setup>后&#xff0c;就没法这么干了整个…

地理服务零成本:免费地图API合辑

在全球化和数字化不断推进的今天&#xff0c;地图已成为我们日常生活和工作中不可或缺的工具。无论是规划日常通勤、探索未知地域&#xff0c;还是进行地理数据分析&#xff0c;地图都发挥着至关重要的作用。它们不仅提供了地理信息的直观表示&#xff0c;还支持复杂的空间查询…

【U8+】登录U8时,选择账套登录窗口闪退。

【问题描述】 打开用友U8企业应用平台登录窗口&#xff0c; 输入账号和密码后&#xff0c;选择账套的时候闪退。 【解决方法】 方法一&#xff1a; 重装微软的silverlight&#xff0c;在U8soft\3rdprogram中有安装包。 注&#xff1a;不要自动更新此程序版本。关闭杀毒软件防火…

【线程安全】线程互斥的原理

文章目录 Linux线程互斥线程互斥相关概念互斥量mutex引出线程并发问题引出互斥锁、互斥量 互斥量的接口初始化互斥量销毁互斥量互斥量加锁和解锁使用互斥锁抢票 可重入和线程安全概念&#xff1a;常见线程不安全的情况常见线程安全的情况常见不可重入的情况常见可重入情况可重入…

jvm 05JVM - 对象的创建 ,oop模型,字符串常量池

01.JVM - 对象的创建 1、对象的创建的方式 Java语言中&#xff0c;对象创建的方式有六种&#xff1a; new关键字&#xff1a;最常见的形式、Xxx的静态方法、XxxBuilder、XxxFactory的静态方法。 Class类的newInstance()方法&#xff1a;通过反射的方式创建对象&#xff0c;调…

92. 反转链表 II (Swift 版本)

题目描述 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的链表 。 分析 这是一个经典的链表问题&#xff0c;要求反转链表的部分节点。我们可以通过以下步骤实…

Codesys 连接 EtherCAT 总线伺服

本文内容是根据参考视频做的笔记&#xff1a; EtherCAT Master 控制&#xff1a;https://www.bilibili.com/video/BV1L14y1t7ks/EtherCAT Master Motion 控制&#xff1a;https://www.bilibili.com/video/BV16P411j71E/ EtherCAT 总线简单介绍 从站站号&#xff1a;如果使用扫…

【pytorch22】激活函数与GPU加速

激活函数 ReLu还是还是可能出现梯度弥散&#xff0c;因为x<0的时候&#xff0c;梯度还是可能小于0 leaky relu&#xff0c;在x<0的时候&#xff0c;梯度就不会为0&#xff0c;梯度不会不动 Relu函数在x0处是不连续的 一种更加光滑的曲线是SELU&#xff0c;是两个函数的…

ESXI6.7升级补丁报错VIB QLC_bootbank_qedrntv

1、报错如下图 2、原因 VMware在下方链接说的很清楚&#xff0c;报错原因为OEM提供的镜像与新版本补丁某些驱动不兼容&#xff1b; https://knowledge.broadcom.com/external/article?legacyId78487https://knowledge.broadcom.com/external/article?legacyId78487 3、解决 …

自动化立体仓库设计步骤:7步

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 完整版文件和更多学习资料&#xff0c;请球友到知识星球【智能仓储物流技术研习社】自行下载 这份文件是关于自动化立体仓库设计步骤的详细指南&#xff0c;其核心内容包括以下几个阶…

Git常用技能速成

文章目录 一.版本控制二.提交并推送代码三.提交推送代码 一.版本控制 接下来&#xff0c;我们就需要对我们的功能进行优化&#xff0c;但是需要说明的是&#xff0c;我们不仅仅要对上述提到的缓存进行优化&#xff0c;还需要对我们程序的各个方面进行优化。我们本章节主要是针…

mirthConnect 常用示例和语法整理

mirthConnect 常用示例和语法整理 1、jolt json常用语法 https://please.blog.csdn.net/article/details/140137463 2、常用方法 2.1 WinningDateUtils 所有的时间工具在WinningDateUtils里面 获取当前时间&#xff1a;var nowStrWinningDateUtils.getStandardNowStr()获取…

【C++】开源:格式化库fmt配置与使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍格式化库fmt配置与使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下…

Android 通知访问权限

问题背景 客户反馈手机扫描三方运动手表&#xff0c;下载app安装后&#xff0c;通知访问权限打不开。 点击提示“受限设置” “出于安全考虑&#xff0c;此设置目前不可用”。 问题分析 1、setting界面搜“授予通知访问权限”&#xff0c;此按钮灰色不可点击&#xff0c;点…

Linux系统下anaconda的安装与Pytorch环境的下载

首先&#xff0c;在命令行通过cd命令&#xff0c;进入用户文件夹 cd xxx/xxx/username进入anaconda官网https://repo.anaconda.com/archive/&#xff0c;寻找anaconda下载包资源&#xff0c;这里选择最新的anaconda下载包 Anaconda3-2024.06-1-Linux-x86_64.sh 在命令行执行安…

项目收获总结--Redis的知识收获

一、概述 最近几天公司项目开发上线完成&#xff0c;做个收获总结吧~ 今天记录Redis的收获和提升。 二、Redis异步队列 Redis做异步队列一般使用 list 结构作为队列&#xff0c;rpush 生产消息&#xff0c;lpop 消费消息。当 lpop 没有消息的时候&#xff0c;要适当sleep再…

土壤检测仪器:精确地检测土壤元素

在农业生产的广阔天地中&#xff0c;土壤检测仪器如同一把钥匙&#xff0c;打开了我们认识土壤、了解土壤元素的大门。这些看似平凡却功能强大的设备&#xff0c;能够精确地检测出土壤中的各种元素&#xff0c;为农业生产提供科学、准确的数据支持。 一、土壤检测仪器的重要性 …

大气热力学(5)——绝热过程

本篇文章源自我在 2021 年暑假自学大气物理相关知识时手写的笔记&#xff0c;现转化为电子版本以作存档。相较于手写笔记&#xff0c;电子版的部分内容有补充和修改。笔记内容大部分为公式的推导过程。 文章目录 5.1 气块的概念5.2 热力学第一定律的几种微分形式5.3 干绝热过程…