【信奥一本通提高篇】基础算法之贪心算法

原文

https://bbs.fmcraft.top/blog/index.php/archives/22/

贪心算法

概述

近年来的信息学竞赛试题,经常出现求一个问题的可行解或最优解的题目。这类问题就是我们通常所说的最优化问题。贪心算法是求解这类问题的一种常用算法。在众多的算法中,贪心算法可以算得上是最接近人们日常思维的一种算法,常被信息学奥赛选手用来求解一些数据规模很大的问题。

一、贪心算法

贪心算法是从问题的初始状态出发,通过若干次的贪心选择而得到的最优值(或较优值)的一种求解问题策略,即贪心策略。
换句话说,贪心策略是一种在每次决策时采取当前意义下最优策略的算法,做出的选择只是在某种约束条件下的局部最优解或较优解,并不一定是全局的最优解或较优解。不过,某些特定的问题是可以利用贪心算法求得其最优解或较优解的。
【引例1】在N行M列的正整数矩阵中,要求从每行中选出一个数,使得选出的N个数的和最大。
分析:本题可以用贪心算法求解。选N次,每一次选出相应行中的最大值即可。
【引例2】在一个N×M的方格阵中,每一格子赋予一个数(即权值),规定每次移动时只能向上或向右。现试找出一条路径,使其从左下角至右上角所经过的权值之和最大。
我们以2×3的矩阵为例:

/列1列2列3
行1346
行21210
若按贪心算法求解,所得路径为:1→3→4→6。
若按动态规划求解,所得路径为:1→2→ 10→6。
显然,这里用贪心算法求解,得到的并不是问题的最优解。

二、贪心算法的特点

1.贪心选择

所谓贪心选择是指应用同一规则,将原问题变为一个相似的但规模更小的子问题,而后的每 一步都是当前看似最佳的选择,且这种选择只依赖于已做出的选择,不依赖于未做出的选择。

最优子结构

执行算法时,每一次得到的结果虽然都是当前问题的最优解(即局部最优解),但只有满足全 局最优解包含局部最优解时,才能保证最终得到的结果是最优解。

三、几个简单的贪心实例

1.最优装载问题

给 n 个物体,第i个物体重量为W₁, 选择尽量多的物体,使得总重量不超过C。
【思路点拨】
由于只关心物体的数量,所以装重的没有装轻的划算。只需把所有物体按重量从小到大排 序,依次选择每个物体,直到装不下为止。这就是一种典型的贪心算法,它只顾眼前,但却能得到全 局最优解。
贪心策略:先装最轻的。

2.部分背包问题

有n 个物体,第i个物体的重量为w₁, 价值为 v₁,在总重量不超过C 的情况下让总价值尽量高。 每一个物体可以只取走一部分,价值和重量按比例计算。
【思路点拨】
本题是在上一题的基础上增加了价值项,所以不能简单地像上一题那样先选出轻的(轻的可 能其价值也小),也不能先拿价值大的(它可能特别重),而应该综合考虑两个因素。一种直观的贪心策略是:优先选出价值与重量的比值最大的,直到重量和正好为C。
注意:由于每个物体可以只选出一部分,因此一定可以让总重量恰好为C(或者所有物体全选,总重量还不足C), 而且除了最后一个以外,所有的物体要么不选,要么全部选。
贪心策略:先选出性价比高的。

3.乘船问题

有n个人,第i个人重量为w,。每艘船的载重量均为C,最多可乘两个人。求用最少的船装载所有人的方案。
【思路点拨】
考虑最轻的人i, 他应该和谁一起乘呢?如果每个人都不能和他一起乘,则只能每人乘一艘船。 否则,他应该选择能和他一起乘的人中最重的一个人j。这样的选择只是让“眼前”的浪费最少,因此它是一种贪心策略。
贪心策略:最轻的人和最重的人配对。
这个贪心策略的正确性和有效性是可以用反证法证明的。
证明:假设这个贪心策略不是最优的,最优方案中的i是什么样的呢?
情况1:i不和任何一个人乘同一艘船,那么可以把j拉过来和他一起乘,总船数不会增加(且可能会减少!),并且符合贪心策略。
情况2:i和另外一个人k同乘一艘船,其中k比j轻。把j和k交换后,j原来所在的船仍然不会超重(因为k比j轻),因此i和j同乘一艘船,所得到的新解不会更差,且符合贪心策略。
由此可见,利用本题的贪心策略求解不会丢失最优解。
程序实现。在前面的分析中,比j更重的人只能每人乘一艘船。这样,我们只需用两个指针i和j分别表示当前考虑的最轻的人和最重的人。每次先将指针j往左移动,直到i和j可以共乘一艘船,然后将指针i往右移,指针j往左移,并重复上述操作,直到所有的人都装载上。不难看出,这 个程序的时间复杂度仅为O(n), 是最优算法。

总结

通过以上3个例子,我们大致了解了贪心算法的形式和正确性证明的基本方法。下面,进一步分析几个经典贪心算法的应用,加深对贪心算法的理解。

四、贪心算法的经典应用

1.选择不相交区间问题

给定n个开区间(a,b),选择尽量多个区间,使得这些区间两两没有公共点。
【思路点拨】
首先,按照b_1<=b_2<=…<=b_n,的顺序排序,依次考虑各个区间,如果没有和已经选择的区间冲突,就选:否则就不选。
【正确性】
假设b_1<b_i且(a_j,b_j)、(a_i,b_i) 分别与之前的区间不冲突,当前选(a_j,b_j).若(a_j,b_j)与(a_j,b_i)不冲突,则还可以选择(a_i,b_i),答案个数加一;若(a_j,b_j)与(a_i,b_i)冲突,因为b_j<b_i,所以选(a_j,b_j)对以后的影响更小。

2.区间选点问题

【问题描述】
给定n个闭区间[a_i,b_i], 在数轴上选尽量少的点,使得每个区间内都至少有一个点(不同区同内含的点可以是同一个)。
【思路点拨】
首先按照区间的结束位置从小到大排序。然后从区间1到区间n 进行选择:对于当前区间,吾 集合中的数不能覆盖它,则将区间末尾的数加入集合。
贪心策略:取最后一个。
如图下图所示,如果选灰色点,则移动到黑色点会更优。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.区间覆盖问题

【问题描述】
给n个闭区间[a_i,b_i],选择尽量少的区间覆盖一条指定的线段区间[s,t]。
【思路点拨】
将所有的区间按左端点从小到大排序,依次处理每个区间。每次选择覆盖点s的区间中右端 点坐标最大的一个,并将s更新为该区间的右端点坐标,直到选择的区间已包含了t为止。
贪心策略:在某个时刻的s, 找一个满足a[i]≤s的b[i]最大值即可。

4.流水作业调度问题

【问题描述】
有n个作业要在两台机器M1和M2组成的流水线上完成加工。每个作业i都必须先花时间a在M上加工,然后花时间b在M2上加工。
确定n个作业的加工顺序,使得从作业1在机器M1上加工开始到作业n在机器M2上加工实完为止所用的总时间最短。
【思路点拨】
直观上,最优调度一定让M1、M2的空闲时间尽量短。
Johnson算法:设N1为a<b的作业集合,N2 为a≥b的作业集合,将N1的作业按a非减序排序,N2中的作业按照b非增序排序,则N1作 业接N2作业构成最优顺序。
算法的程序易于实现,时间复杂度为O(nlogn),正确性需要证明。

5.带限期和罚款的单位时间任务调度

【问题描述】
有n个任务,每个任务都需要1个时间单位执行,任务i的截止时间d_i(1≤d≤n)表示要求任务i在时问d_i结束时必须完成,误时惩罚w_i表示若任务i未在时间d_i结束之前完成,将导致w_i的罚款。
确定所有任务的执行顺序,使得惩罚最少。
【思路点拨】
要使罚款最少.我们显然应尽量完成w[i]值较大的任务。
此时,我们可以将任务按w[i]从大到小进行排序,然后按照排好的顺序依次对任务进行安排。 安排的规则为:使处理任务i的时间既在d[i]之内,又尽量靠后;如果d[i]之内的时间都已经排满,就放弃处理此项任务。
【算法证明】
假设按照上述算法得到的解不是最优的,那么必然存在某个任务j应当安排到处理的过程中 但却没有安排。假设我们要将该任务安排进去,由于在时间d[j]内都已经排满,就必然需要将一个已安排的任务k与之替换,而w[k]≥w[j]。 这样,替换显然会增加罚款的数额、因此,除上还安排方法以外的安排方法都不会使罚款的数额减少,可知用上述算法得到的结果是最优的。
【实现方法】
①先按照罚款数额从大到小快排。
②顺序处理每个任务,若能安排,则找一个最晚时间:否则放在最后的空位上。

练习

如需练习学习的内容,可自行寻找相关题目。
也可以前往FMCRAFT OJ做题。下面的地址可以直接跳转到其相关题目一本通训练中的题单 算法训练中的题单。使用OJ前需要注册账户。

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

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

相关文章

CentOS-7.0系统基础操作

配置ip地址 编辑网卡文件&#xff1a; vi etc/sysconfig/network-scripts/ifcfg-ens33 在网卡文件里参照如下设置&#xff1a; BOOTPROTO"static" IPADDR192.168.61.233 GATEWAY192.168.61.2 NETMASK255.255.255.0 ONBOOT"yes" 防火墙管理 开启防火墙&am…

【大模型应用】信息抽取的调研

老规矩&#xff0c;先占坑&#xff0c;后续更新。 关键词&#xff1a; Pydantic functioncal 参考文献&#xff1a;小白学大模型&#xff1a;自定义信息抽取Agent-CSDN博客

MySQL内存使用率高问题排查与解决方案:

目录标题 **一、问题现象****二、核心排查步骤****1. 参数检查****2. 内存使用分析****3. 存储过程/函数/视图检查****4. 操作系统级检查** **三、解决方案****1. 调整MySQL配置****2. 关闭透明大页&#xff08;THP&#xff09;****3. 优化查询与存储过程****4. 硬件与环境优化…

华为GaussDB数据库的手动备份与还原操作介绍

数据库的备份以A机上的操作为例。 1、使用linux的root用户登录到GaussDB服务器。 2、用以下命令切换到 GaussDB 管理员用户&#xff0c;其中&#xff0c;omm 为当前数据库的linux账号。 su - omm 3、执行gs_dump命令进行数据库备份&#xff1a; 这里使用gs_dump命令进行备…

How to install OpenJ9 JDK 17 on Ubuntu 24.04

概述 OpenJ9 是一款由 IBM 开发并开源的 Java 虚拟机&#xff08;JVM&#xff09;&#xff0c;现由 ​Eclipse 基金会管理&#xff08;名为 ​Eclipse OpenJ9&#xff09;。它旨在提供高性能、低内存消耗和快速启动时间&#xff0c;特别适用于云原生和容器化环境。 关键特性 …

洛谷题单1-P5705 【深基2.例7】数字反转-python-流程图重构

题目描述 输入一个不小于 100 100 100 且小于 1000 1000 1000&#xff0c;同时包括小数点后一位的一个浮点数&#xff0c;例如 123.4 123.4 123.4 &#xff0c;要求把这个数字翻转过来&#xff0c;变成 4.321 4.321 4.321 并输出。 输入格式 一行一个浮点数 输出格式 …

【云服务器】在Linux CentOS 7上快速搭建我的世界 Minecraft 服务器搭建,并实现远程联机,详细教程

【云服务器】在Linux CentOS 7上快速搭建我的世界 Minecraft 服务器搭建&#xff0c;详细详细教程 一、 服务器介绍二、下载 Minecraft 服务端三、安装 JDK 21四、搭建服务器五、本地测试连接六、添加服务&#xff0c;并设置开机自启动 前言&#xff1a; 推荐使用云服务器部署&…

内网穿透_ZeroTiers部署_广和通SC171_aidlux_嵌入式

下载 sudo curl -s https://install.zerotier.com | sudo bash &#xff08;需要科学上网&#xff09; 所有涉及硬件的操作好像都需要 root 权限&#xff0c;curl 在这里需要连接网络&#xff0c;所以也需要 sudo sudo zerotier-cli status 若返回 200 info 及设备 ID&#xff…

Faster RCNN Pytorch 实现 代码级 详解

基本结构&#xff1a; 采用VGG提取特征的Faster RCNN. self.backbone:提取出特征图->features self.rpn:选出推荐框->proposals self.roi heads:根据proposals在features上进行抠图->detections features self.backbone(images.tensors)proposals, proposal_losses…

【Matlab】-- 基于MATLAB的美赛常用多种算法

文章目录 文章目录 01 内容概要02 各种算法基本原理03 部分代码04 代码下载 01 内容概要 本资料集合了多种数学建模和优化算法的常用代码资源&#xff0c;旨在为参与美国大学生数学建模竞赛&#xff08;MCM/ICM&#xff0c;简称美赛&#xff09;的参赛者提供实用的编程工具和…

Vue2和Vue3响应式的基本实现

目录 简介Vue2 响应式Vue2 响应式的局限性 Vue3 响应式Vue3 响应式的优点 Vue2 和 Vue3 响应式对比 简介 在 Vue 框架中&#xff0c;数据的响应式是其核心特性之一。当页面数据发生变化时&#xff0c;我们希望界面能自动更新&#xff0c;而不是手动操作 DOM。这就需要对数据进…

Linux系统中快速安装docker

1 查看是否安装docker 要检查Ubuntu是否安装了Docker&#xff0c;可以使用以下几种方法&#xff1a; 方法1&#xff1a;使用 docker --version 命令 docker --version如果Docker已安装&#xff0c;输出会显示Docker的版本信息&#xff0c;例如&#xff1a; Docker version …

ElasticSearch 分词器

文章目录 一、安装中文分词插件Linux安装7.14.1版本&#xff1a;测试1&#xff1a;ik_smart测试2&#xff1a;ik_max_word 二、es内置的分词器&#xff1a;三、拼音插件安装以及&#xff08;IKpinyin使用&#xff09;配置 IK pinyin 分词配置 一、安装中文分词插件 IK Analys…

arm64位FFmpeg与X264库

参考链接&#xff1a; https://blog.csdn.net/gitblog_09700/article/details/142945092

机器学习与深度学习4:数据集处理Dataset,DataLoader,batch_size

深度学习中&#xff0c;我们能看到别人的代码中都有一个继承Dataset类的数据集处理过程&#xff0c;这也是深度学习处理数据集的的基础&#xff0c;下面介绍这个数据集的定义和使用&#xff1a; 1、数据集加载 1.1 通用的定义 Bach&#xff1a;表示每次喂给模型的数据 Epoc…

MySQL数据库和表的操作之SQL语句

&#x1f3af; 本文专栏&#xff1a;MySQL深入浅出 &#x1f680; 作者主页&#xff1a;小度爱学习 MySQL数据库和表的操作 关系型数据库&#xff0c;都是遵循SQL语法进行数据查询和管理的。 SQL语句 什么是sql SQL&#xff1a;结构化查询语言(Structured Query Language)&…

ubuntu开发mcu环境

# 编辑 vim或者vscode # 编译 arm-none-eabi # 烧写 openocd 若是默认安装&#xff0c;会在/usr/share/openocd/scripts/{interface,target} 有配置接口和目标版配置 示例&#xff1a; openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg 启动后&#xff0c;会…

Windows模仿Mac大小写切换, 中英文切换

CapsLock 功能优化脚本部署指南 部署步骤 第一步&#xff1a;安装 AutoHotkey v2 访问 AutoHotkey v2 官网下载并安装最新版本安装时勾选 "Add Compile Script to context menus" 第二步&#xff1a;部署脚本 直接运行 (调试推荐) 新建文本文件&#xff0c;粘贴…

Selenium Web自动化如何快速又准确的定位元素路径,强调一遍是元素路径

如果文章对你有用&#xff0c;请给个赞&#xff01; 匹配的ChromeDriver和浏览器版本是更好完成自动化的基础&#xff0c;可以从这里去下载驱动程序&#xff1a; 最全ChromeDriver下载含win linux mac 最新版本134.0.6998.165 持续更新..._chromedriver 134-CSDN博客 如果你问…

CSRF vs SSRF详解

一、CSRF&#xff08;跨站请求伪造&#xff09;攻击全解 攻击原理示意图 受害者浏览器 ├── 已登录银行网站&#xff08;Cookie存活&#xff09; └── 访问恶意网站执行&#xff1a;<img src"http://bank.com/transfer?tohacker&amount1000000">核心…