青少年编程与数学 02-018 C++数据结构与算法 16课题、贪心算法

青少年编程与数学 02-018 C++数据结构与算法 16课题、贪心算法

  • 一、贪心算法的基本概念
    • 定义
    • 组成部分
  • 二、贪心算法的工作原理
  • 三、贪心算法的优点
  • 四、贪心算法的缺点
  • 五、贪心算法的应用实例
    • (一)找零问题
      • 问题描述:
      • 贪心策略:
      • 示例代码:
      • 解释:
    • (二)活动安排问题
      • 问题描述:
      • 贪心策略:
      • 示例代码:
      • 解释:
    • (三)霍夫曼编码
      • 问题描述:
      • 贪心策略:
      • 示例代码:
      • 解释:
    • (四)最小生成树(Kruskal算法)
      • 问题描述:
      • 贪心策略:
      • 示例代码:
      • 解释:
  • 六、总结

课题摘要:
贪心算法(Greedy Algorithm)是一种在每一步选择中都采取当前状态下最优(即最有利)的选择,从而希望导致结果是全局最优的算法。贪心算法并不总是能得到最优解,但它在很多问题上都能得到较好的近似解,并且通常具有较高的效率。


一、贪心算法的基本概念

定义

贪心算法在每一步选择中都采取当前状态下最优的选择,从而希望导致结果是全局最优的。这种“最优”通常是根据某种局部标准来衡量的。

组成部分

  1. 贪心选择性质:问题的整体最优解可以通过一系列局部最优的选择来达到。这是贪心算法可行的基本要素。
  2. 最优子结构:问题的最优解包含其子问题的最优解。贪心算法通过分解问题为更小的子问题来逐步构建全局最优解。
  3. 贪心策略:一种用于选择局部最优解的策略,通常基于某种特定的规则或标准。

二、贪心算法的工作原理

  1. 贪心选择:在每一步选择中,根据某种贪心策略选择当前状态下最优的选项。例如,在找零问题中,每次选择面值最大的硬币。
  2. 构建解:通过一系列的贪心选择逐步构建解。每一步的选择都是基于当前状态的最优选择,而不考虑后续步骤。
  3. 验证:在某些情况下,需要验证通过贪心选择得到的解是否满足问题的约束条件。如果满足,则该解是全局最优解;如果不满足,则需要重新考虑贪心策略。

三、贪心算法的优点

  1. 简单直观:贪心算法的逻辑通常比较简单,容易理解和实现。
  2. 效率高:贪心算法通常具有较高的效率,因为它不需要像动态规划那样存储大量的子问题解。
  3. 适用性广:贪心算法可以应用于多种问题,尤其是在组合优化问题中。

四、贪心算法的缺点

  1. 不能保证全局最优:贪心算法只能保证在每一步选择中是局部最优的,但不能保证最终结果是全局最优的。例如,在某些背包问题中,贪心算法可能无法找到最优解。
  2. 适用范围有限:贪心算法只能应用于具有贪心选择性质和最优子结构的问题。对于不满足这些条件的问题,贪心算法可能无法得到正确的解。

五、贪心算法的应用实例

(一)找零问题

问题描述:

给定一组硬币面值和一个金额,求用最少的硬币数凑成该金额。

贪心策略:

每次选择面值最大的硬币。

示例代码:

#include <iostream>
#include <vector>
#include <algorithm>int coin_change(const std::vector<int>& coins, int amount) {std::vector<int> sorted_coins = coins;std::sort(sorted_coins.rbegin(), sorted_coins.rend());int count = 0;for (int coin : sorted_coins) {while (amount >= coin) {amount -= coin;count++;}}return amount == 0 ? count : -1;
}

解释:

每次选择面值最大的硬币,直到金额为0。

(二)活动安排问题

问题描述:

给定一组活动的开始时间和结束时间,求最多可以安排多少个不冲突的活动。

贪心策略:

每次选择结束时间最早的活动。

示例代码:

#include <iostream>
#include <vector>
#include <algorithm>int activity_selection(const std::vector<int>& start, const std::vector<int>& finish) {std::vector<std::pair<int, int>> activities;for (size_t i = 0; i < start.size(); ++i) {activities.emplace_back(start[i], finish[i]);}std::sort(activities.begin(), activities.end(), [](const auto& a, const auto& b) {return a.second < b.second;});int count = 0;int last_finish = 0;for (const auto& activity : activities) {if (activity.first >= last_finish) {count++;last_finish = activity.second;}}return count;
}

解释:

每次选择结束时间最早的活动,确保后续活动不冲突。

(三)霍夫曼编码

问题描述:

给定一组字符及其频率,求一种最优的编码方式,使得编码后的字符串长度最短。

贪心策略:

每次选择频率最小的两个字符合并。

示例代码:

#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>
#include <string>struct Node {char ch;int freq;Node* left;Node* right;Node(char ch, int freq) : ch(ch), freq(freq), left(nullptr), right(nullptr) {}
};struct Compare {bool operator()(Node* left, Node* right) {return left->freq > right->freq;}
};void build_codes(Node* root, const std::string& prefix, std::unordered_map<char, std::string>& codes) {if (!root) return;if (root->ch != '\0') {codes[root->ch] = prefix;}build_codes(root->left, prefix + "0", codes);build_codes(root->right, prefix + "1", codes);
}std::unordered_map<char, std::string> huffman_encoding(const std::unordered_map<char, int>& frequencies) {std::priority_queue<Node*, std::vector<Node*>, Compare> pq;for (const auto& entry : frequencies) {pq.push(new Node(entry.first, entry.second));}while (pq.size() > 1) {Node* left = pq.top(); pq.pop();Node* right = pq.top(); pq.pop();Node* merged = new Node('\0', left->freq + right->freq);merged->left = left;merged->right = right;pq.push(merged);}std::unordered_map<char, std::string> codes;build_codes(pq.top(), "", codes);return codes;
}int main() {std::unordered_map<char, int> frequencies = {{'a', 5}, {'b', 9}, {'c', 12}, {'d', 13}, {'e', 16}, {'f', 45}};auto codes = huffman_encoding(frequencies);for (const auto& entry : codes) {std::cout << entry.first << ": " << entry.second << std::endl;}return 0;
}

解释:

通过构建霍夫曼树,为每个字符分配最优的编码。

(四)最小生成树(Kruskal算法)

问题描述:

给定一个加权无向图,求一个最小生成树。

贪心策略:

每次选择权重最小的边,确保不形成环。

示例代码:

#include <iostream>
#include <vector>
#include <algorithm>class UnionFind {
public:UnionFind(int n) : parent(n) {for (int i = 0; i < n; ++i) {parent[i] = i;}}int find(int x) {if (parent[x] != x) {parent[x] = find(parent[x]);}return parent[x];}void union_sets(int x, int y) {int rootX = find(x);int rootY = find(y);if (rootX != rootY) {parent[rootX] = rootY;}}private:std::vector<int> parent;
};std::vector<std::tuple<int, int, int>> kruskal(const std::vector<std::tuple<int, int, int>>& edges, int n) {std::vector<std::tuple<int, int, int>> mst;UnionFind uf(n);std::vector<std::tuple<int, int, int>> sorted_edges(edges.begin(), edges.end());std::sort(sorted_edges.begin(), sorted_edges.end(), [](const auto& a, const auto& b) {return std::get<2>(a) < std::get<2>(b);});for (const auto& edge : sorted_edges) {int u = std::get<0>(edge);int v = std::get<1>(edge);int weight = std::get<2>(edge);if (uf.find(u) != uf.find(v)) {uf.union_sets(u, v);mst.push_back(edge);}}return mst;
}int main() {std::vector<std::tuple<int, int, int>> edges = {{0, 1, 2}, {1, 2, 3}, {2, 3, 1}, {3, 0, 4}, {0, 2, 5}};int n = 4;auto mst = kruskal(edges, n);for (const auto& edge : mst) {std::cout << std::get<0>(edge) << " - " << std::get<1>(edge) << " : " << std::get<2>(edge) << std::endl;}return 0;
}

解释:

通过选择权重最小的边,逐步构建最小生成树。

六、总结

贪心算法是一种简单而高效的算法设计策略,适用于具有贪心选择性质和最优子结构的问题。它通过在每一步选择中采取当前状态下最优的选择,逐步构建解。虽然贪心算法不能保证总是得到全局最优解,但在很多实际问题中都能得到较好的近似解。在使用贪心算法时,需要仔细分析问题的性质,确保贪心策略的有效性。

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

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

相关文章

UE5 Set actor Location和 Set World Location 和 Set Relative Location 的区别

在 Unreal Engine 的蓝图里&#xff0c;SetRelativeLocation、SetWorldLocation 和 SetActorLocation 三个节点虽然都能改变物体位置&#xff0c;但作用对象和坐标空间&#xff08;Coordinate Space&#xff09;不同&#xff1a; 1. SetActorLocation 作用对象&#xff1a;整个…

VINS-FUSION:跑通手机录制数据

文章目录 &#x1f4da;简介&#x1f680;手机录制数据&#x1f680;跑通数据&#x1f527;启动rviz&#x1f527;启动配置&#x1f527;播放rosbag&#x1f3af;跑通结果 &#x1f4da;简介 利用智能手机的 摄像头IMU 采集数据&#xff0c;并在 VINS-Fusion&#xff08;视觉惯…

Spring AI在大模型领域的趋势场景题深度解析

Spring AI在大模型领域的趋势场景题深度解析 在互联网大厂Java求职者的面试中&#xff0c;经常会被问到关于Spring AI在大模型领域的趋势场景的相关问题。本文通过一个故事场景来展示这些问题的实际解决方案。 第一轮提问 面试官&#xff1a;马架构&#xff0c;欢迎来到我们…

MySQL数据库全面详解:从基础到高级应用

一、数据存储概述 在计算机系统中&#xff0c;数据可以存储在多种形式中&#xff1a; 变量&#xff1a;程序中最基本的数据存储单元 元组&#xff1a;不可变的序列类型&#xff0c;常用于函数返回多个值 列表&#xff1a;有序可变集合&#xff0c;可存储不同类型元素 字典&…

Redux和MobX有什么区别

Redux 和 MobX 都是用于 React 应用的全局状态管理库&#xff0c;但它们在设计理念、使用方式和适用场景等方面存在明显的区别&#xff0c;下面为你详细分析&#xff1a; 1. 设计理念 Redux&#xff1a;基于 Flux 架构&#xff0c;遵循单向数据流和纯函数式编程的理念。状态是…

WPF实现类似Microsoft Visual Studio2022界面效果及动态生成界面技术

WPF实现类似VS2022界面效果及动态生成界面技术 一、实现类似VS2022界面效果 1. 主窗口布局与主题 <!-- MainWindow.xaml --> <Window x:Class"VsStyleApp.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x…

备份服务器,备份服务器数据有哪些方法可以实现?

服务器承载着企业核心业务数据与关键应用&#xff0c;数据丢失或业务中断可能带来灾难性后果。因此&#xff0c;构建一套科学、可靠的服务器数据备份体系至关重要。当前&#xff0c;服务器数据备份方法可根据技术架构、存储介质及恢复需求进行多维划分。根据不同场景、预算和技…

前端基础——5、CSS border属性与渐变色(详解与实战)

前端基础——5、CSS border属性与渐变色详解 CSS border属性与渐变色&#xff08;详解与实战&#xff09;一、border属性全面解析1. 基础三属性2. 复合写法3. 高级特性附加.border-style详解使用示例效果&#xff1a; CSS 渐变终极指南&#xff1a;线性渐变与径向渐变的深度解析…

企业出海降本:如何将应用从 AWS EC2 快速无缝迁移至DigitalOcean Droplet

企业出海已经成为目前最热门的趋势。然而不论你是做跨境电商&#xff0c;还是短剧出海&#xff0c;或处于最热门的AI 赛道&#xff0c;你都需要使用海外的云主机或GPU云服务。海外一线的云服务平台尽管覆盖区域广泛&#xff0c;但是往往费用成本较高。所以降本始终是企业出海关…

解决Spring Boot多模块自动配置失效问题

前言 在Spring Boot多模块项目中&#xff0c;模块间配置不生效是一个复杂但可解决的问题&#xff0c;尤其涉及自动配置类、依赖冲突、条件注解以及IDE配置。 一、问题背景与场景 1.1 场景描述 假设存在两个模块&#xff1a; 模块A&#xff1a;提供通用配置&#xff08;如跨…

WEBSTORM前端 —— 第2章:CSS —— 第4节:盒子模型

目录 1.画盒子 2.Pxcook软件 3.盒子模型——组成 4.盒子模型 ——边框线 5.盒子模型——内外边距 6.盒子模型——尺寸计算 7.清除默认样式 8.盒子模型——元素溢出 9.外边距问题 ①合并现象 ②塌陷问题 10.行内元素——内外边距问题 11.盒子模型——圆角 12.盒子…

Kafka和flume整合

需求1&#xff1a;利用flume监控某目录中新生成的文件&#xff0c;将监控到的变更数据发送给kafka&#xff0c;kafka将收到的数据打印到控制台&#xff1a; 在flume/conf下添加.conf文件&#xff0c; vi flume-kafka.conf # 定义 Agent 组件 a1.sourcesr1 a1.sinksk1 a1.c…

Idea 如何配合 grep console过滤并分析文件

这里写自定义目录标题 [grep console插件]()右击打开文件目录&#xff0c;选择 tail in console 同时可以添加自己的快捷键。 ![新的改变](https://i-blog.csdnimg.cn/direct/03423e27cf6c40c5abd2d53982547b61.png) 随后会在idea的菜单栏中出现tail菜单。这里&#xff0c;接下…

怎样学习Electron

学习 Electron 是一个很好的选择&#xff0c;特别是如果你想构建跨平台的桌面应用程序&#xff0c;并且已经有前端开发经验。以下是一个循序渐进的学习指南&#xff0c;帮助你从零开始掌握 Electron。 1. 基础知识 HTML/CSS/JavaScript 确保你对这些基础技术有扎实的理解&am…

MySQL 大数据量分页查询优化指南

问题分析 当对包含50万条记录的edu_test表进行分页查询时&#xff0c;发现随着分页越深入&#xff0c;查询时间越长&#xff1a; limit 0,10&#xff1a;0.05秒limit 200000,10&#xff1a;0.14秒limit 499000,10&#xff1a;0.21秒 通过EXPLAIN分析发现&#xff0c;limit o…

【仿真】Ubuntu 22.04 安装MuJoCo 3.3.2

官方GIthub下载: https://github.com/google-deepmind/mujoco/releases 官网&#xff1a;MuJoCo — Advanced Physics Simulation 文档&#xff1a;Overview - MuJoCo Documentation 主要参考&#xff1a;Ubuntu 22.04 安装Mujoco 3.22 - RobotStudent的文章 - 知乎 简…

最新字节跳动运维云原生面经分享

继续分享最新的go面经。 今天分享的是组织内部的朋友在字节的go运维工程师岗位的云原生方向的面经&#xff0c;涉及Prometheus、Kubernetes、CI/CD、网络代理、MySQL主从、Redis哨兵、系统调优及基础命令行工具等知识点&#xff0c;问题我都整理在下面了 面经详解 Prometheus …

PyQt6实例_pyqtgraph散点图显示工具_代码分享

目录 描述&#xff1a; 效果&#xff1a; 代码&#xff1a; 返回结果对象 字符型横坐标 通用散点图工具 工具主界面 使用举例 描述&#xff1a; 1 本例结合实际应用场景描述散点图的使用。在财报分析中&#xff0c;需要将数值放在同行业中进行比较&#xff0c;从而判…

纯C协程框架NtyCo

原文是由写的&#xff0c;写的真的很好&#xff0c;原文链接&#xff1a;纯c协程框架NtyCo实现与原理-CSDN博客 1.为什么会有协程&#xff0c;协程解决了什么问题&#xff1f; 网络IO优化 在CS&#xff0c;BS的开发模式下&#xff0c;服务器的吞吐量是一个受关注的参数&#x…

信息系统项目管理师——第10章 项目进度管理 笔记

10项目进度管理 1.规划进度管理&#xff1a;项目章程、项目管理计划&#xff08;开发方法、范围管理计划&#xff09;、事业环境因素、组织过程资产——专家判断、数据分析&#xff08;备选方案分析&#xff09;、会议——进度管理计划 2.定义活动&#xff1a;WBS进一步分解&am…