当前位置: 首页 > news >正文

算法之贪心(简)

贪心算法(Greedy Algorithm)

贪心算法是一种局部最优导向的启发式算法,核心思想是:在每一步决策中,都选择当前状态下的最优解(局部最优),并期望通过一系列局部最优的选择,最终得到全局最优解。

需要注意的是,贪心算法并非适用于所有问题 —— 它的有效性依赖于问题是否具备「贪心选择性质」(局部最优决策能导出全局最优)和「最优子结构性质」(全局最优解包含子问题的最优解)。若问题不满足这两个性质,贪心算法可能只能得到近似解。

一、核心特性

1. 贪心选择性质

每次选择仅依赖当前局部信息,不回溯、不考虑未来决策的影响。例如,找零问题中,每次优先选面值最大的硬币,就是典型的局部最优选择。

2. 最优子结构性质

全局最优解可以通过一系列局部最优解的组合得到。例如,最短路径问题中,从起点到终点的最短路径,包含了路径上任意两个中间节点之间的最短路径。

3. 无后效性

一旦做出选择,就无法更改,后续决策仅基于当前的选择结果,不依赖之前未选择的路径。

二、算法步骤

  1. 问题分解:将原问题分解为多个相互独立的子问题(或步骤)。
  2. 局部最优选择:对每个子问题,选择当前状态下的最优解(需定义明确的 “最优” 标准,如最大、最小、代价最低等)。
  3. 合并结果:将所有局部最优解组合,形成原问题的最终解。

三、经典应用场景

1. 找零问题(硬币找零)

  • 问题:给定不同面值的硬币(如 1 元、5 元、10 元、20 元),用最少的硬币数量凑出指定金额。
  • 贪心策略:每次优先选择面值最大的硬币,直到凑出目标金额。
  • 适用条件:硬币系统需满足 “贪心选择性质”(如人民币、美元的硬币系统);若硬币面值特殊(如 1 元、3 元、4 元),贪心可能失效(例如凑 6 元:贪心选 4+1+1=3 枚,最优解是 3+3=2 枚)。

2. 活动选择问题

  • 问题:给定多个互不重叠的活动(每个活动有开始时间和结束时间),选择最多的活动,使得它们互不冲突。
  • 贪心策略:优先选择结束时间最早的活动,为后续活动预留更多时间。
  • 示例:活动集合 [(1,4), (3,5), (0,6), (5,7), (3,9), (5,9), (6,10), (8,11), (8,12), (2,14), (12,16)],最优解是选择 (1,4), (5,7), (8,11), (12,16),共 4 个活动。

3. 最小生成树(MST)

  • 问题:带权连通无向图中,找到总权重最小的生成树(包含所有顶点,边数为 n-1,无环)。
  • 贪心策略
    • Prim 算法:从起始顶点出发,每次选择连接 “已选顶点集” 和 “未选顶点集” 的权重最小的边。
    • Kruskal 算法:按边权重升序排序,每次选择不形成环的权重最小边。

4. 单源最短路径(Dijkstra 算法)

  • 问题:带权有向图中,找到从起点到其他所有顶点的最短路径(边权重非负)。
  • 贪心策略:每次选择当前距离起点最近的未访问顶点,更新其邻接顶点的距离。

5. 哈夫曼编码(Huffman Coding)

  • 问题:为字符设计前缀编码,使得总编码长度最短(压缩数据)。
  • 贪心策略:每次选择出现频率最低的两个节点合并,生成新节点,重复直到形成一棵哈夫曼树,树的路径即为字符的编码(左 0 右 1 或反之)。

四、优缺点

优点

  • 效率高:步骤简单,无需回溯,时间复杂度通常较低(如 O (n log n),主要来自排序)。
  • 实现简洁:逻辑直观,代码容易编写和维护。

缺点

  • 局限性强:仅适用于具备 “贪心选择性质” 和 “最优子结构” 的问题,否则可能得到次优解。
  • 无法回溯:一旦做出决策就无法更改,若局部最优选择导致后续陷入死局,无法调整。

五、代码示例(活动选择问题)

以 “选择最多不冲突活动” 为例,展示贪心算法的实现:

cpp

运行

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;// 活动结构体:开始时间start,结束时间end
struct Activity {int start;int end;
};// 排序规则:按结束时间升序排列
bool compare(const Activity& a, const Activity& b) {return a.end < b.end;
}// 贪心选择最多不冲突活动
vector<Activity> selectMaxActivities(vector<Activity>& activities) {vector<Activity> result;if (activities.empty()) return result;// 1. 按结束时间排序sort(activities.begin(), activities.end(), compare);// 2. 选择第一个活动(结束时间最早)result.push_back(activities[0]);int lastEnd = activities[0].end;// 3. 遍历后续活动,选择与上一个活动不冲突的(开始时间>=上一个结束时间)for (int i = 1; i < activities.size(); i++) {if (activities[i].start >= lastEnd) {result.push_back(activities[i]);lastEnd = activities[i].end;}}return result;
}int main() {vector<Activity> activities = {{1,4}, {3,5}, {0,6}, {5,7}, {3,9},{5,9}, {6,10}, {8,11}, {8,12}, {2,14}, {12,16}};vector<Activity> selected = selectMaxActivities(activities);cout << "选择的活动数量:" << selected.size() << endl;cout << "活动详情:" << endl;for (auto& act : selected) {cout << "(" << act.start << ", " << act.end << ")" << endl;}return 0;
}

输出结果

plaintext

选择的活动数量:4
活动详情:
(1, 4)
(5, 7)
(8, 11)
(12, 16)

六、贪心算法与其他算法的区别

1. 与动态规划的区别

  • 贪心:局部最优导向,无回溯,适合子问题独立的场景。
  • 动态规划:全局最优导向,通过存储子问题的最优解避免重复计算,适合子问题重叠、需要回溯的场景(如背包问题)。

2. 与回溯法的区别

  • 贪心:不探索所有可能路径,仅选局部最优,效率高但可能非全局最优。
  • 回溯法:探索所有可能路径,能找到全局最优,但时间复杂度高(如排列组合问题)。

总结

贪心算法是一种高效的启发式算法,核心是 “局部最优导出全局最优”。它适用于特定类型的问题(如活动选择、最小生成树、哈夫曼编码等),在工程实践中常用于追求高效解的场景。使用时需先验证问题是否具备贪心选择性质,否则需考虑动态规划、回溯法等其他算法。

http://www.dtcms.com/a/503650.html

相关文章:

  • Linux小课堂: 软件安装机制深度解析之以 CentOS 为例的 RPM 包管理与 YUM 工具详解
  • Spring Boot 3零基础教程,WEB 开发 请求路径匹配规则 笔记32
  • 深入理解HTML文本标签:构建网页内容的基础
  • WebP、J2k、Ico、Gif、Cur、Png图片批量转换软件
  • 手机wap网站 源码网站开发报价 福州
  • 网站建设营销推广优秀网站建设模板
  • 【计算机算法与分析】基于比较的排序算法
  • 排序算法(1)--- 插入排序
  • css总结
  • WPS Office 11.8.2.12085 Portable_Win中文_办公软件_便携版安装教程
  • 广州网站建设 易企建站公司网页制作软件序列号
  • 斯坦福大学 | CS336 | 从零开始构建语言模型 | Spring 2025 | 笔记 | Lecture 5: GPUs
  • 做淘宝需要的网站手机网站建设平台
  • 密码学和分布式账本
  • Web后端登录认证(会话技术)
  • 网络安全 | SSL/TLS 证书文件格式详解:PEM、CRT、CER、DER、PKI、PKCS12
  • uploads-labs靶场通关(2)
  • wordpress 企业建站小程序模板源码免费
  • Linux中页表缓存初始化pgtable_cache_init函数的实现
  • 量子计算机会普及个人使用吗?
  • 嵌入式入门:APP+BSP+HAL 三层分级架构浅析
  • 使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 19--测试框架Pytest基础 3--前后置操作应用
  • 面试面试面试
  • 北京响应式的网站下载了模板如何做网站
  • 中山企业营销型网站制作wordpress亲你迷路了
  • 个人做电影网站有什么风险南山最专业的网站建设
  • 「用Python来学微积分」4. 极坐标方程与参数方程
  • 第六章 路由基础
  • P1049 装箱问题 题解(四种方法)附DP和DFS的对比
  • Windows下Vscode连接到WSL的方法