【数据结构和算法】-贪心算法

贪心算法(又称贪婪算法)是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法。贪心算法在有最优子结构的问题中尤为有效,它通过将问题分解为一系列更小的子问题,并依次解决这些子问题,从而得到原问题的解。

贪心算法的基本思路是从问题的某一个初始解出发,逐步逼近给定的目标,以尽可能快地求得更好的解。当某个步骤不能再继续前进时,算法就停止执行。贪心算法并不是对所有问题都能得到整体最优解,关键是贪心策略的选择。选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关。

贪心算法的主要特点包括:

  1. 局部最优选择:在每一步,算法都根据某种局部最优的准则进行选择,以期望通过这种方式得到全局最优解。
  2. 简化问题:每做一次贪心选择,就将所求问题简化为一个规模更小的子问题。
  3. 迭代进行:贪心算法通常以自顶向下的方式进行,通过迭代的方法逐步得到问题的解。

贪心算法可以解决的问题通常具有一些特殊的性质,如贪心选择性质和最优子结构性质。贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择来达到。最优子结构性质是指问题的最优解包含其子问题的最优解。这些性质是贪心算法能够成功解决问题的关键。
接下来我们看几个例子:

找零问题

一个贪心算法的实际例子是找零问题,即给定一些面值的硬币,如何用最少数量的硬币来凑齐一个给定的金额。这个问题可以使用贪心算法来解决,基本思路是从面值最大的硬币开始,尽可能多地使用这种硬币,直到剩余的金额无法再使用这种硬币为止,然后转而使用面值次大的硬币,依此类推。

例如,假设我们有面值为1元、50分、25分、10分、5分和1分的硬币,我们需要凑齐93分。按照贪心算法的思想,我们可以按照硬币面值从大到小的顺序进行考虑:

  1. 首先考虑面值最大的1元硬币,但93分不足以使用1元硬币,所以我们跳过1元硬币。
  2. 接着考虑50分硬币,因为93分大于50分,所以我们可以使用一枚50分硬币,此时剩余金额为43分。
  3. 然后考虑25分硬币,因为43分大于25分,所以我们可以使用一枚25分硬币,此时剩余金额为18分。
  4. 接下来考虑10分硬币,因为18分大于10分,所以我们可以使用一枚10分硬币,此时剩余金额为8分。
  5. 再考虑5分硬币,因为8分大于5分,所以我们可以使用一枚5分硬币,此时剩余金额为3分。
  6. 最后,我们使用三枚1分硬币来凑齐剩余的3分。

通过贪心算法,我们使用了6枚硬币来凑齐93分,这是使用最少数量硬币的方法。

需要注意的是,贪心算法并不总是能得到最优解,但在某些情况下,如硬币找零问题中硬币面值设计合理时,贪心算法可以得到最优解。因此,在选择使用贪心算法时,需要确保问题满足贪心算法的前提条件和特性。

以下是使用贪心算法解决找零问题的 Python 代码示例:

def make_change(amount, coins):# coins 列表应按照面值从大到小的顺序排列coins.sort(reverse=True)change = []  # 用于存储找零的硬币列表remaining = amount  # 剩余需要凑齐的金额for coin in coins:# 当剩余金额大于等于当前硬币的面值时,就使用该硬币while remaining >= coin:change.append(coin)remaining -= coin# 如果剩余金额已经为0,则无需继续考虑后面的硬币if remaining == 0:break# 如果最终剩余金额不为0,说明无法用给定的硬币凑齐if remaining != 0:return None  # 或者可以抛出异常或返回其他错误标识return change# 示例:假设有面值为 [1, 5, 10, 25] 的硬币,需要凑齐93分
coins = [1, 5, 10, 25]
amount = 93
change_list = make_change(amount, coins)if change_list is not None:print("找零的硬币列表为:", change_list)print("所需硬币总数为:", len(change_list))
else:print("无法用给定的硬币凑齐金额")

在这段代码中,我们首先定义了一个函数 make_change,它接受两个参数:amount(需要凑齐的金额)和 coins(可用的硬币面值列表)。然后,我们按照硬币面值从大到小的顺序对硬币进行排序。接着,我们遍历排序后的硬币列表,尽可能多地使用当前硬币来凑齐剩余金额,直到剩余金额为0或者无法再使用当前硬币为止。最后,我们检查是否还有剩余的金额无法凑齐,如果有则返回 None 或抛出异常,否则返回找零的硬币列表。

注意,这段代码假设硬币面值列表已经按照从大到小的顺序排列。如果硬币面值列表未排序,你需要在调用 make_change 函数之前先对 coins 进行排序。此外,这段代码只考虑了找零硬币的数量,没有考虑找零硬币的总面值是否等于原始金额,这在实际情况中通常是隐含的,因为每一步都是根据剩余金额来选取硬币的。

网络路由流量分配

实际生产中,贪心算法常用于各种优化问题,其中一个常见的例子是在网络路由中使用贪心算法进行流量分配。下面我将给出一个简化的例子,即使用贪心算法解决带权重的网络流量分配问题。

假设我们有一个网络,其中节点代表路由器或交换机,边代表它们之间的连接,边的权重代表连接的带宽。我们的目标是分配流量,使得每条连接的带宽都得到充分利用,同时避免过载。

为了简化问题,我们假设每个节点都有一个固定的流量需求,流量只能从源节点流向目标节点,且每条边的带宽都是固定的。贪心策略可以是每次选择剩余带宽最大的边来分配流量。

以下是一个简单的 Python 代码示例,用于解决这个问题:

import heapq
from collections import defaultdictclass Network:def __init__(self, edges, demands):# edges: [(source, target, capacity), ...]# demands: {source: target_demand, ...}self.graph = defaultdict(list)self.capacities = {}self.demands = demandsself.allocated = defaultdict(int)for source, target, capacity in edges:self.graph[source].append(target)self.graph[target].append(source)self.capacities[(source, target)] = capacityself.capacities[(target, source)] = capacity# 初始化最大堆,按照剩余带宽从大到小排序self.max_heap = [(capacity, source, target) for source, target, capacity in edges]heapq.heapify(self.max_heap)def allocate_flow(self):while self.max_heap:capacity, source, target = heapq.heappop(self.max_heap)# 如果源节点的需求已经被满足,则跳过if self.allocated[source] >= self.demands[source]:continue# 计算可以分配的流量allocatable = min(capacity - self.allocated[(source, target)], self.demands[source] - self.allocated[source])# 分配流量self.allocated[(source, target)] += allocatableself.allocated[source] += allocatable# 更新剩余带宽到最大堆中remaining_capacity = capacity - self.allocated[(source, target)]if remaining_capacity > 0:heapq.heappush(self.max_heap, (remaining_capacity, source, target))# 检查是否所有需求都已满足if self.allocated[source] == self.demands[source]:break# 检查是否所有需求都得到满足return all(allocated == demand for source, demand in self.demands.items() for allocated in [self.allocated[source], self.allocated.get((source, target), 0][::2])# 示例使用
edges = [('A', 'B', 10),('A', 'C', 5),('B', 'C', 8),('B', 'D', 7),('C', 'D', 6)
]
demands = {'A': 8, 'B': 4, 'C': 2}network = Network(edges, demands)
if network.allocate_flow():print("流量分配成功!")for source, target in network.capacities:print(f"从 {source}{target} 分配了 {network.allocated[(source, target)]} 单位流量")
else:print("流量分配失败,无法满足所有需求!")

在这个示例中,Network 类表示网络,它维护了一个图结构(通过邻接表表示)以及每条边的带宽。allocate_flow 方法使用贪心策略来分配流量,每次都从剩余带宽最大的边开始分配。如果成功分配了所有流量,它会打印出每条边分配的流量;否则,它会报告分配失败。

注意,这个简化示例没有考虑许多实际网络流量分配问题中的复杂因素,比如流量的动态变化、多路径路由、故障恢复等。在实际生产环境中,网络流量分配通常更加复杂,并且会结合其他算法和技术来实现高效和可靠的流量管理。

贪心算法的前提条件和特性

贪心算法需要满足的前提条件和特性主要包括以下几点:

  1. 最优子结构:问题的最优解可以通过子问题的最优解来推导得到。这意味着,如果我们将问题分解为若干个子问题,并且每个子问题都使用了贪心策略得到最优解,那么由这些子问题的最优解组合起来就能得到原问题的全局最优解。

  2. 贪心选择性质:每一步的最优选择都可以导致最终的全局最优解。也就是说,贪心算法在每一步都做出在当前看来最好的选择,并希望这样的局部最优选择能够导致全局最优解。这种性质要求我们在设计贪心算法时,能够确定每一步的局部最优选择策略。

  3. 无后效性:即某个状态以后的过程不会影响以前的状态,只与当前状态有关。这意味着贪心算法在做出选择后,不会因为后面的选择而改变之前的选择。

  4. 可行性:贪心算法所做出的选择必须是可行的,即必须满足问题的约束条件。

贪心是解决局部最优,大家一定要注意,并不一定是全局最优,全局最优需要用到其他的比如动态规划等算法。后续我们会逐步介绍。

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

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

相关文章

使用SpringBoot实现定时任务

在Spring Boot中实现定时任务非常简单,主要通过使用Scheduled注解。Spring Boot的Scheduled注解提供了一种简单的、声明式的方式来定义定时任务。这些任务可以按照指定的时间间隔执行,无需手动管理线程或定时器。下面是如何使用Spring Boot来实现定时任务…

linux ,Windows部署

Linux部署 准备好虚拟机 连接好查看版本:java -version安装jdk 解压命令:tar -zxvf 加jdk的压缩文件名cd /etc 在编辑vim profile文件 在最底下写入: export JAVA_HOME/root/soft/jdk1.8.0_151(跟自己的jdk保持一致&#xff0…

python 之pymongo的CURD

文章目录 pymongo的基本操作前言新增1、新增一条记录2、新增多条记录3、自定义_id 的新增 更新1、更新一条记录2、更新多条记录 删除删除一条记录删除多条记录 查询条件查询根据运算符查询根据范围查找根据正则表达式查询投影排序分页查询 管道聚合 pymongo的基本操作 前言 前…

SpringSecurity 快速入门

文章目录 1. 认证授权概述1.1 认证授权概念1.1.1 认证1.1.2 授权 1.2 权限数据模型1.3 RBAC权限模型1.3.1 介绍1.3.2 基于角色访问控制1.3.3 基于资源访问控制 1.4 常见认证方式1.4.1 Cookie-Session1.4.2 jwt令牌无状态认证 1.5 技术实现 2. SpringSecurity入门2.1 介绍2.2 入…

突破编程_C++_设计模式(迭代模式)

1 迭代模式的基本概念 在 C 中,迭代模式是一种常见的设计模式,它用于遍历或处理集合中的元素。迭代模式允许程序员在不了解集合内部表示的情况下,以一种统一和一致的方式来访问集合中的元素。这种模式的核心是迭代器对象,它封装了…

「CISP题库精讲」CISP题库习题解析精讲20道

前言 本篇主要对CISP教材第九章《计算环境安全》的一些习题进行讲解,包括20道题,这里只是部分习题,针对第九章可能会多写几章的内容,如果我发布的这些习题里面没有你想找的那道题,你也可以直接私信我,我加…

「连载」边缘计算(二十九)03-11:边缘部分源码(源码分析篇)

(接上篇) EdgeCore之matamanager 前面对EdgeCore组件的edged、devicetwin、edgehub、eventbus功能模块进行了分析,本节对EdgeCore组件的另一个功能模块metamanager进行剖析。metamanager作为EdgeCore中的edged模块与edgehub模块进行交互的桥…

求根节点到叶节点数字之和

题目链接 求根节点到叶节点数字之和 题目描述 注意点 树中节点的数目在范围 [1, 1000] 内0 < Node.val < 9树的深度不超过10 解答思路 深度优先遍历计算从根节点到叶子节点组成的所有数字&#xff08;每向下一层乘以10&#xff09;&#xff0c;再计算所有的数字之和…

中小型生产企业工业数据采集分析平台 规划生产流程

工业数据采集分析平台是一款优秀的工控自动化软件&#xff0c;可以用于数据采集、实时监测和过程控制、数据传输、系统联动、远程监控等多种应用&#xff0c;数据采集平台通过对设备运行状态及相关参数监视实现保证每个环节都能按照既定方案进行&#xff0c;同时缩短非正常停机…

shiro整合thymeleaf(接上一篇抛出的问题)

在上一篇末尾&#xff0c;讲到如何实现不同身份的用户&#xff0c;有不同的权限&#xff0c;从而看到不同的页面&#xff0c;下面我们就来实现下这个功能 1.导入依赖 <!--shiro整合thymeleaf--><dependency><groupId>com.github.theborakompanioni</group…

python(ogr)处理geojson为本地shp文件

前言 本次所利用的geojson数据来自https://geo.datav.aliyun.com/areas_v3/bound/410000_full.json &#xff0c;如果觉得下方代码看起来不方便&#xff0c;可以来GitHub上来看&#xff0c;在这上面还有一些辅助内容便于理解 GISpjd/GIS-union-Python (github.com)https://gi…

14.WEB渗透测试--Kali Linux(二)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;13.WEB渗透测试--Kali Linux&#xff08;一&#xff09;-CSDN博客 netcat简介内容:13.WE…

精品基于Springboot的体育用品租赁租用管理系统的设计与实现

《[含文档PPT源码等]精品基于Springboot的体育用品管理系统的设计与实现[包运行成功]》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 软件开发环境及开发工具&#xff1a; Java——涉及技术&#xff1a; 前端使用技术&…

c# DbHelper的封装

c# DbHelper的封装 基于ADO.NET框架&#xff0c;封装了适用于多个关系型数据库的DbHelper。通过简洁明了的代码&#xff0c;实现了对各种数据库的高效操作。 public class DbHelper{private readonly DataBase _dataBase;public DbHelper(DataBase dataBase){_dataBase data…

SpringCloud-实现基于RabbitMQ的消息队列

消息队列是现代分布式系统中常用的通信机制&#xff0c;用于在不同的服务之间传递消息。在Spring Cloud框架中&#xff0c;我们可以利用RabbitMQ实现强大而可靠的消息队列系统。本篇博客将详细介绍如何在Spring Cloud项目中集成RabbitMQ&#xff0c;并创建一个简单的消息队列。…

【Kotlin】类和对象

1 前言 Kotlin 是面向对象编程语言&#xff0c;与 Java 语言类似&#xff0c;都有类、对象、属性、构造函数、成员函数&#xff0c;都有封装、继承、多态三大特性&#xff0c;不同点如下。 Java 有静态&#xff08;static&#xff09;代码块&#xff0c;Kotlin 没有&#xff1…

Spring AOP常见面试题

目录 一、对于AOP的理解 二、Spring是如何实现AOP的 1、execution表达式 2、annotation 3、基于Spring API&#xff0c;通过xml配置的方式。 4、基于代理实现 三、Spring AOP的实现原理 四、Spring是如何选择使用哪种动态代理 1、Spring Framework 2、Spring Boot 五…

博士推荐 | 纤维与聚合物科学博士,功能性纺织品研发主管

编辑 / 木子 审核 / 朝阳 伟骅英才 伟骅英才致力于以大数据、区块链、AI人工智能等前沿技术打造开放的人力资本生态&#xff0c;用科技解决职业领域问题&#xff0c;提升行业数字化服务水平&#xff0c;提供创新型的产业与人才一体化服务的人力资源解决方案和示范平台&#x…

二分查找【详解】

本期介绍&#x1f356; 主要介绍&#xff1a;二分查找的简单思路&#xff0c;为什么必须在有序的前提下才能使用二分查找&#xff0c;该怎么用C程序来实现二分查找&#xff0c;二分查找的局限性&#x1f440;。 文章目录 1. 题目2. 思路3. 前提条件4. 编写程序 1. 题目 在一个有…

选择性遗忘可以帮助人工智能学得更好?

最近&#xff0c;一些计算机科学家创建了一种更灵活、更灵巧的机器学习模型。诀窍在于&#xff1a;它必须定期忘记它所知道的信息。虽然这种新方法不会取代支撑最大应用程序的庞大模型&#xff0c;但它能揭示这些程序如何理解语言的更多信息。 &#xff08;PS&#xff1a;如果…