贪心算法教程(个人总结版)

背景

贪心算法(Greedy Algorithm)是一种在每一步选择中都采取在当前状态下最好或最优的选择,期望通过局部最优选择达到全局最优解决方案的算法。贪心算法的应用广泛,包括图算法、动态规划、贪心选择、装载问题等。它通常用于解决优化问题,例如最短路径、最小生成树、背包问题等。

贪心算法的基本思想

贪心算法的核心思想是,在每一步都选择当前最优解,以期最终达到全局最优。贪心算法通常包括以下几个要素:

  1. 贪心选择性质:可以通过局部最优选择构造出全局最优解。
  2. 最优子结构性质:一个问题的最优解包含其子问题的最优解。

贪心算法的应用

贪心算法在许多经典问题中有着广泛的应用,如:

  1. 活动选择问题:选择不重叠的最大活动集合。
  2. 背包问题:选择最大价值的物品装入背包。
  3. 哈夫曼编码:构造最优前缀码。
  4. 最小生成树问题:如Prim算法和Kruskal算法。
  5. 最短路径问题:如Dijkstra算法。

贪心算法的实现

1. 活动选择问题

问题描述

给定一组活动,每个活动有一个开始时间和结束时间。要求选择尽可能多的互不重叠的活动。

贪心策略

每次选择结束时间最早且不与已选活动重叠的活动。

算法实现
def activity_selection(activities):# 按照结束时间排序activities.sort(key=lambda x: x[1])# 选择活动selected_activities = []last_end_time = 0for activity in activities:if activity[0] >= last_end_time:selected_activities.append(activity)last_end_time = activity[1]return selected_activities# 示例
activities = [(1, 4), (3, 5), (0, 6), (5, 7), (3, 8), (5, 9), (6, 10), (8, 11), (8, 12), (2, 13), (12, 14)]
selected_activities = activity_selection(activities)
print("选择的活动:", selected_activities)
详细解释
  1. 排序:首先按照活动的结束时间对活动进行排序。
  2. 选择活动:遍历排序后的活动列表,每次选择第一个不与已选择活动重叠的活动。
  3. 更新结束时间:每次选择一个活动后,更新最后选择的活动的结束时间。

2. 背包问题

背包问题是经典的优化问题之一,其中包括0-1背包问题和分数背包问题。贪心算法主要适用于分数背包问题。

分数背包问题

分数背包问题允许将物品分割,目的是在总重量不超过背包容量的情况下,选择最大价值的物品集合。

贪心策略

每次选择单位重量价值最高的物品。

算法实现
def fractional_knapsack(items, capacity):# 计算单位重量价值items.sort(key=lambda x: x[1] / x[0], reverse=True)total_value = 0for weight, value in items:if capacity >= weight:total_value += valuecapacity -= weightelse:total_value += value * (capacity / weight)breakreturn total_value# 示例
items = [(2, 10), (3, 5), (5, 15), (7, 7), (1, 6), (4, 18), (1, 3)]
capacity = 15
max_value = fractional_knapsack(items, capacity)
print("最大价值:", max_value)
详细解释
  1. 排序:按照物品的单位重量价值排序。
  2. 选择物品:遍历排序后的物品列表,每次选择单位重量价值最高的物品,直到背包装满。
  3. 处理剩余空间:如果剩余容量小于当前物品的重量,则只取一部分物品。

3. 哈夫曼编码

哈夫曼编码是一种用于数据压缩的贪心算法。

问题描述

给定一组字符及其频率,构造一棵哈夫曼树,使得字符的平均编码长度最短。

贪心策略

每次选择频率最小的两个节点合并。

算法实现
import heapqclass Node:def __init__(self, freq, symbol, left=None, right=None):self.freq = freqself.symbol = symbolself.left = leftself.right = rightself.huff = ''def __lt__(self, nxt):return self.freq < nxt.freqdef huffman_coding(symbols):heap = [Node(freq, symbol) for symbol, freq in symbols]heapq.heapify(heap)while len(heap) > 1:left = heapq.heappop(heap)right = heapq.heappop(heap)left.huff = '0'right.huff = '1'new_node = Node(left.freq + right.freq, left.symbol + right.symbol, left, right)heapq.heappush(heap, new_node)return heap[0]def print_huffman_tree(node, val=''):new_val = val + node.huffif node.left:print_huffman_tree(node.left, new_val)if node.right:print_huffman_tree(node.right, new_val)if not node.left and not node.right:print(f"{node.symbol}: {new_val}")# 示例
symbols = [('A', 5), ('B', 9), ('C', 12), ('D', 13), ('E', 16), ('F', 45)]
huffman_tree = huffman_coding(symbols)
print_huffman_tree(huffman_tree)
详细解释
  1. 初始化:将每个字符及其频率创建为一个节点,并加入优先队列(最小堆)。
  2. 合并节点:每次从堆中取出频率最小的两个节点,合并为一个新的节点,将新节点加入堆中。
  3. 构建哈夫曼树:重复上述过程,直到堆中只剩一个节点,这个节点即为哈夫曼树的根节点。
  4. 生成编码:从根节点开始,左子树路径为'0',右子树路径为'1',遍历树生成每个字符的哈夫曼编码。

4. 最小生成树问题

最小生成树问题是图论中的经典问题之一,常用的贪心算法有Prim算法和Kruskal算法。

Prim算法

Prim算法用于找到一个连通图的最小生成树,选择从某个顶点开始,每次选择与当前树相连的权重最小的边。

算法实现
import heapqdef prim(graph, start):mst = []visited = set()min_heap = [(0, start)]while min_heap:weight, node = heapq.heappop(min_heap)if node not in visited:visited.add(node)mst.append((weight, node))for next_node, next_weight in graph[node]:if next_node not in visited:heapq.heappush(min_heap, (next_weight, next_node))return mst# 示例
graph = {'A': [('B', 1), ('C', 3), ('D', 4)],'B': [('A', 1), ('C', 2), ('D', 5)],'C': [('A', 3), ('B', 2), ('D', 6)],'D': [('A', 4), ('B', 5), ('C', 6)]
}
mst = prim(graph, 'A')
print("最小生成树:", mst)
详细解释
  1. 初始化:从起始顶点开始,将所有相邻边加入优先队列(最小堆)。
  2. 选择边:每次选择权重最小的边,若边的终点未被访问过,则将其加入生成树,并将该顶点的所有相邻边加入堆中。
  3. 重复步骤:直到所有顶点都被访问过,生成树构建完成。

5. 最短路径问题

最短路径问题是图论中的另一个经典问题,Dijkstra算法是常用的贪心算法之一。

Dijkstra算法

Dijkstra算法用于找到从单个源点到所有其他顶点的最短路径,每次选择当前已知最短路径的顶点,并更新其邻接顶点的距离。

算法实现
import heapqdef dijkstra(graph, start):distances = {vertex: float('infinity') for vertex in graph}distances[start] = 0priority_queue = [(0, start)]while priority_queue:current_distance, current_vertex = heapq.heappop(priority_queue)if current_distance > distances[current_vertex]:continuefor neighbor, weight in graph[current_vertex]:distance = current_distance + weightif distance < distances[neighbor]:distances[neighbor] = distanceheapq.heappush(priority_queue, (distance, neighbor))return distances# 示例
graph = {'A': [('B', 1), ('C', 4)],'B': [('A', 1), ('C', 2), ('D', 5)],'C': [('A', 4), ('B', 2), ('D', 1)],'D': [('B', 5), ('C', 1)]
}
distances = dijkstra(graph, 'A')
print("最短路径:", distances)
详细解释
  1. 初始化:设置所有顶点到源点的初始距离为无穷大,源点到自身距离为0,将源点加入优先队列。
  2. 选择顶点:每次选择距离最小的顶点,若当前顶点的距离已被更新,则跳过。
  3. 更新邻接顶点的距离:对于当前顶点的每个邻接顶点,计算从源点到该邻接顶点的距离,若新距离小于当前已知距离,则更新并将其加入优先队列。
  4. 重复步骤:直到优先队列为空,所有顶点的最短路径计算完成。

贪心算法的优缺点

优点

  1. 简单易懂:贪心算法的思想简单明了,容易理解和实现。
  2. 高效:贪心算法通常具有较低的时间复杂度,适合处理大规模数据。
  3. 适用于某些特定问题:在一些特定问题中,贪心算法可以快速找到最优解,如最小生成树、最短路径等。

缺点

  1. 局部最优不保证全局最优:贪心算法通过局部最优选择来构建全局解,但在某些情况下,局部最优选择可能导致最终解并非全局最优。
  2. 问题依赖性强:贪心算法适用于特定问题,不能普遍适用于所有问题。

结论

贪心算法是一种强大而高效的算法,广泛应用于各种优化问题中。通过对贪心选择性质和最优子结构性质的理解,可以设计出适合特定问题的贪心算法。在实践中,应根据具体问题的特点选择合适的算法,以充分发挥其优势。

通过本教程的详细介绍和代码示例,希望您对贪心算法有了更深入的理解,并能够在实际项目中应用这些技术。

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

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

相关文章

【C++】---二叉搜索树

【C】---二叉搜索树 一、二叉搜索树概念二、二叉搜索树操作&#xff08;非递归&#xff09;1.二叉搜索树的查找 &#xff08;非递归&#xff09;&#xff08;1&#xff09;查找&#xff08;2&#xff09;中序遍历 2.二叉搜索树的插入&#xff08;非递归&#xff09;3.二叉搜索树…

Java 实现二叉搜索树 代码

新建文件 创建TreeNode类&#xff0c;实例化 直接在BinarySearchTree类里面写就可以 static class TreeNode {public int key;public TreeNode left;public TreeNode right;TreeNode(int key) {this.key key;}}public TreeNode root; 插入节点 insert public boolean inser…

Spring创建对象的多种方式

一、对象分类 简单对象&#xff1a;使用new Obj()方式创建的对象 复杂对象&#xff1a;无法使用new Obj()方式创建的对象。例如&#xff1a; 1. AOP创建代理对象。ProxyFactoryBean; 2. Mybatis中的SqlSessionFactoryBean; 3. Hibernate中的SessionFactoryBean。二、创建对象方…

创新案例 | 持续增长,好孩子集团的全球化品牌矩阵战略与客户中心设计哲学

探索好孩子集团如何通过创新设计的全球化品牌矩阵和以客户为中心的产品策略&#xff0c;在竞争激烈的母婴市场中实现持续增长。深入了解其品牌价值观、市场定位策略以及如何满足新一代父母的需求。本文旨在为中高级职场人士、创业家及创新精英提供深度见解&#xff0c;帮助他们…

最新上市公司控制变量大全(1413+指标)1990-2023年

数据介绍&#xff1a;根据2023年上市公司年报数据进行更新&#xff0c;包括基本信息、财务指标、环境、社会与治理、数字化转型、企业发展、全要素生产率等1413指标。数据范围&#xff1a;A股上市公司数据年份&#xff1a;1990-2023年指标数目&#xff1a;1413个指标&#xff0…

在云中确保安全的五个技巧

随着采用云计算战略并开始充分意识到云计算技术可以提供的回报&#xff0c;企业可以做些什么来改善他们的风险状况?以下是德迅云安全在云中确保安全的五个技巧。 德迅云安全对如何在云计算基础设施中确保安全的五个技巧进行了阐述和分析。 在当今的混合工作环境中&#xff0c…

UG NX二次开发(C#)-UFun函数-利用UFPart.Export导出模型中的对象并创建一个新的part

文章目录 1、前言2、UF_PART_export函数定义3、UF_PART_export_with_options函数定义4、代码1、前言 在UG NX 10.0二次开发中,需要用到将装配体中通过几何建模创建的对象独立创建一个part文件,所以查找了下UFun函数,即是UF_PART_export 和UF_PART_export_with_options两个函…

在Windows 10中,如何利用命令提示符删除应用程序

如果你使用的是Windows 10&#xff0c;并且需要释放一些磁盘空间&#xff0c;你可以直接从命令提示符卸载不再使用的应用程序。以下是操作方法。 首先&#xff0c;你必须以管理员身份运行命令提示符才能卸载程序。在“Windows搜索”框中&#xff0c;键入“cmd”或“命令提示符…

NVR对接三方相机预览黑屏问题案例

一、 问题现象 【问题现象】NVR接入三方相机,通道状态显示在线,但本地、web预览显示黑屏。更换H.264&#xff0c;H.265均预览黑屏&#xff0c;且NVR侧的萤石云手机APP预览报错260025。 【现场拓扑】现场拓扑如下 &#xff08;1&#xff09; IPC使用onvif协议添加至NVR&#xff…

程序猿转型做项目经理一定要注意这 5 个坑

前言 国内的信息系统项目经理&#xff0c;很多都是从技术骨干转型的&#xff0c;我就是这样一路走过来的&#xff0c;这样有很多好处&#xff0c;比如技术过硬容易服众、熟悉开发流程更容易把控项目进度和质量、开发过程中碰到难题时更好组织攻坚等等&#xff0c;但是所谓成也…

Flutter 中的 IndexedStack 小部件:全面指南

Flutter 中的 IndexedStack 小部件&#xff1a;全面指南 Flutter 是一个功能强大的 UI 框架&#xff0c;它提供了多种方式来构建动态和响应式的用户界面。IndexedStack 是 Flutter 中的一个有趣的小部件&#xff0c;它允许开发者根据索引值来显示一组子元素中的一个。这使得 I…

SpringBootWeb 篇-深入了解会话技术与会话跟踪三种技术(Cookie 会话跟踪、Session 会话跟踪与 JWT 令牌会话跟踪)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 会话技术 2.0 会话跟踪 2.1 会话跟踪 - Cookie 2.1.1 客户端获取 Cookie 的流程 2.1.2 Cookie 会话跟踪的特点 2.2 会话跟踪 - Session 2.2.1 客户端获取 SESSION…

C++设计模式-单例模式,反汇编

文章目录 25. 单例模式25.1. 饿汉式单例模式25.2. 懒汉式单例模式25.2.1. 解决方案125.2.2. 解决方案2 &#xff08;推荐写法&#xff09; 运行在VS2022&#xff0c;x86&#xff0c;Debug下。 25. 单例模式 单例即该类只能有一个实例。 应用&#xff1a;如在游戏开发中&#x…

【漏洞复现】大华智能物联综合管理平台 log4j远程代码执行漏洞

0x01 产品简介 大华ICC智能物联综合管理平台对技术组件进行模块化和松耦合&#xff0c;将解决方案分层分级&#xff0c;提高面向智慧物联的数据接入与生态合作能力。 0x02 漏洞概述 大华ICC智能物联综合管理平台/evo-apigw/evo-brm/1.2.0/user/is-exist 接口处存在 l0g4i远程…

【1.文件和目录相关(上)】

一、Linux的文件系统结构 1、Linux文件系统就是一个树形的分层组织结构。 2、文件系统层次结构标准FHS&#xff1a;用于规范文件目录命名和存放标准。 &#xff08;1&#xff09;/bin:是二进制英文缩写。 &#xff08;2&#xff09;/boot:存放的是系统启动时要用到的程序。 …

python -【四】函数

函数 一、函数的基础 函数&#xff1a;是组织好的&#xff0c;可以重复使用的&#xff0c;用来实现特定功能的代码段 语法 def 函数名(入参): return 出参 # 定义函数 def out_hello():print(hello ~~~)# 调用/使用/执行函数 out_hello()练习题 自定义一个函数&#xff0c…

如何配置才能连接远程服务器上的 redis server ?

文章目录 Intro修改点 Intro 以阿里云服为例。 首先&#xff0c;我在我买的阿里云服务器中以下载源码、手动编译的方式安装了 redis-server&#xff0c;操作流程见&#xff1a;Ubuntu redis 下载解压配置使用及密码管理 && 包管理工具联网安装。 接着&#xff0c;我…

Java中的ORM框架——myBatis

一、什么是ORM ORM 的全称是 Object Relational Mapping。Object代表应用程序中的对象&#xff0c;Relational表示的是关系型数据库&#xff0c;Mapping即是映射。结合起来就是在程序中的对象和关系型数据库之间建立映射关系&#xff0c;这样就可以用面向对象的方式&#xff0c…

【UE 反射】反射的原理是什么?如何使用机制?

目录 0 拓展0.1 静态类型检查0.1.1 静态类型检查的主要原理0.1.2 编译器的工作流程0.1.3 静态类型检查的优点和缺点0.1.4 示例0.1.5 C也可以在运行时类型检查RTTI基本原理RTTI的实现RTTI的工作流程RTTI的限制 0.2 运行时动态类型检查0.2.1 主要特点0.2.2 动态类型检查的实现0.2…

56.野指针和悬空指针

一.野指针 野指针指的是指针指向的地址是未知的&#xff08;随机的&#xff0c;不正确的地址&#xff09;。 二.野指针出现的几种情况 1.定义指针未初始化 #include <stdio.h>int main(void) {int *p;*p 1;printf("*p is %d\n",*p); } 正确写法&#xff1…