数据结构----------贪心算法

什么是贪心算法?

贪心算法(Greedy Algorithm)是一种在问题求解过程中,每一步都采取当前状态下最优(即最有利)的选择,从而希望导致最终的全局最优解的算法策略。
贪心算法的核心思想是做选择时,每一步只考虑当前情况的最佳选择,不考虑整体情况,也不考虑这个选择将如何影响未来的选择。
下面是贪心算法的一些基本特点:

  1. 局部最优选择:在每一步选择中都采取当前状态下最优的选择。
  2. 不可回溯:一旦做出了选择,就不可撤销,也就是选择了某一部分的解之后,就不再考虑这个选择之前的其他可能性。
  3. 最优子结构:问题的最优解包含其子问题的最优解,子问题的最优解能被合并为问题的最优解。
    贪心算法适用于具有“最优子结构”和“贪心选择性质”的问题。
    以下是一些可以用贪心算法解决的问题的例子:
  • 找零问题:给出一个金额,如何用最少数量的硬币找零。
  • 哈夫曼编码:用于数据压缩的最优前缀编码方法。
  • 图的最小生成树:例如普里姆算法(Prim’s Algorithm)和克鲁斯卡尔算法(Kruskal’s Algorithm)。
  • 图的最短路径问题:迪杰斯特拉算法(Dijkstra’s Algorithm)在某些条件下可以看作是贪心算法。

贪心算法的步骤通常如下:
4. 初始化:根据问题设定,选择一个初始解作为当前解。
5. 选择:根据某种贪心标准,从候选集合中选出最优解的一个元素,并将它添加到当前解中。
6. 更新:根据上一步的选择,更新候选集合,排除不再可行的选项。
7. 循环:重复“选择”和“更新”步骤,直到达到问题的解。
贪心算法并不总是能得到最优解,它只有在问题具有贪心选择性质时才有效。对于一些问题,贪心算法可以得到最优解,而对于其他问题,贪心算法可能只能得到近似最优解。
贪心算法虽然简单高效,但在某些问题上可能无法得到最优解。以下是贪心算法的一些局限性:
8. 不能保证全局最优解:贪心算法在选择每一步的局部最优解时,可能不会导致全局最优解。这是因为贪心算法没有从整体的角度考虑问题,而是基于当前情况做出选择。
9. 不可回溯:贪心算法一旦做出选择,就不会撤销这个选择,即使这个选择后来被证明是错误的。这种不可回溯的特性意味着贪心算法可能无法纠正之前的错误选择。
10. 不适用于所有问题:贪心算法只适用于具有“贪心选择性质”和“最优子结构”的问题。如果一个问题不满足这些特性,贪心算法就不能保证找到最优解。

在这里插入图片描述

谈心算法的局限性

以下是贪心算法局限性的具体例子:

  • 组合问题:在组合问题中,选择一个元素可能会影响其他元素的选择。贪心算法可能无法处理这种相互依赖的情况。
  • 需要考虑所有可能组合的问题:对于需要考虑所有可能组合的问题,贪心算法可能无法工作,因为它只考虑当前的最优选择,而不是所有可能的组合。
  • 动态规划问题:对于需要考虑过去选择对未来决策影响的问题,贪心算法通常不是最佳选择。动态规划算法更适合这类问题,因为它考虑了所有可能的选择。
    以下是贪心算法局限性的具体表现:
  • 不能处理具有重叠子问题的情况:贪心算法通常不适用于具有重叠子问题的问题,因为它不会存储子问题的解以供后续使用。
  • 可能需要额外的数据结构来支持:在某些情况下,贪心算法可能需要额外的数据结构(如优先队列)来有效地选择下一个最优元素,这可能会增加算法的复杂度。
  • 局部最优解可能不构成全局最优解:在某些问题中,局部最优解的集合并不一定能够组合成全局最优解。
  • 难以证明最优性:对于某些问题,证明贪心算法的最优性可能非常困难,甚至是不可能的。
    因此,在使用贪心算法时,需要仔细分析问题是否适合贪心策略,以及是否存在更有效的算法(如动态规划、回溯算法等)来解决问题。

在这里插入图片描述

贪心算法和动态规划的区别是什么?

贪心算法和动态规划是两种不同的算法设计技术,它们在解决问题的方式上有显著的区别。以下是它们之间的一些主要区别:

  1. 问题解决策略
    • 贪心算法:在每一步选择中都采取当前状态下最优的选择,即局部最优解,不考虑这一选择将如何影响未来的选择。
    • 动态规划:将复杂问题分解为多个子问题,每个子问题只解决一次,并将子问题的解存储起来以供后续使用,从而避免重复计算。
  2. 最优子结构
    • 贪心算法:通常假设通过局部最优选择可以构造出全局最优解,但这并不总是成立。
    • 动态规划:明确利用问题的最优子结构性质,即问题的最优解包含其子问题的最优解。
  3. 决策过程
    • 贪心算法:做出决策后通常不可回溯,一旦选择了某个选项,就会一直使用这个选项。
    • 动态规划:考虑所有可能的决策,并选择导致最优解的决策路径。
  4. 适用范围
    • 贪心算法:适用于具有贪心选择性质的问题,即局部最优选择能导致全局最优解。
    • 动态规划:适用于具有重叠子问题和最优子结构性质的问题。
  5. 算法复杂度
    • 贪心算法:通常实现简单,运行效率高,但可能无法保证找到最优解。
    • 动态规划:可能需要更多的计算和存储空间,因为它需要存储所有子问题的解,但可以保证找到最优解。
  6. 正确性证明
    • 贪心算法:证明其正确性通常比较困难,需要证明局部最优解能组合成全局最优解。
    • 动态规划:正确性通常基于数学归纳法,通过证明最优解包含子问题最优解来证明。
  7. 例子
    • 贪心算法:找零问题、哈夫曼编码、图的最小生成树(如克鲁斯卡尔算法)。
    • 动态规划:背包问题、最长公共子序列、最短路径问题(如贝尔曼-福特算法)。
      总结来说,贪心算法是一种简化版的动态规划,它在每一步都做出最优选择,而不考虑这个选择对未来决策的影响。动态规划则考虑所有可能的决策,并通过子问题的最优解来构造全局最优解。贪心算法在某些问题上可能非常高效,但它不一定能找到最优解,而动态规划则可以保证在适用的问题上找到最优解。

在这里插入图片描述

贪心算法上楼梯

"贪心算法上楼梯"这个问题通常可以这样描述:假设你正在上楼梯,每次可以向上走1步、2步或3步,问到达楼梯顶部有多少种不同的走法。
这个问题实际上并不适合直接用贪心算法来解决,因为贪心算法在选择每一步时只考虑当前最优的选择,而不考虑未来的影响。在这个楼梯问题中,贪心选择并不一定能得到最优解,因为可能需要根据剩余楼梯的步数来调整每一步的选择。
不过,如果我们假设每一步都可以选择走1步、2步或3步,并且我们希望用最少的步数到达楼梯顶部,那么我们可以尝试用贪心算法的思想来解决这个问题。以下是使用贪心算法解决这个问题的步骤:

  1. 初始化:确定楼梯的总步数n
  2. 贪心选择:在每一步尽可能多地走,优先选择3步,然后是2步,最后是1步。
  3. 计算步数:根据楼梯的总步数n,计算每一步选择的次数。
    下面是一个简单的实现:
#include <stdio.h>
// 使用贪心算法计算上楼梯的最少步数
void greedyStairs(int n) {int steps = 0; // 总步数int threeSteps = 0; // 走3步的次数int twoSteps = 0; // 走2步的次数int oneStep = 0; // 走1步的次数// 首先尽可能多地走3步threeSteps = n / 3;n -= threeSteps * 3;// 然后尽可能多地走2步twoSteps = n / 2;n -= twoSteps * 2;// 最后走剩下的1步oneStep = n;// 输出结果printf("走3步的次数: %d\n", threeSteps);printf("走2步的次数: %d\n", twoSteps);printf("走1步的次数: %d\n", oneStep);printf("总步数: %d\n", threeSteps + twoSteps + oneStep);
}
int main() {int n;printf("请输入楼梯的总步数: ");scanf("%d", &n);greedyStairs(n);return 0;
}

请注意,这个贪心算法的实现仅仅计算了到达楼梯顶部所需的最少步数,并没有计算出所有可能的走法。实际上,要计算所有可能的走法,通常需要使用动态规划或递归算法。

贪心算法找零

在这里插入图片描述

贪心算法的一个经典例子是找零问题。在这个问题中,你有一个收银机,里面有一定数量的硬币,比如1元、5元、10元、20元和50元。当顾客需要找零时,你的目标是使用最少数量的硬币来凑成所需找零的金额。
以下是使用贪心算法解决找零问题的步骤:

  1. 初始化:确定需要找零的金额。
  2. 贪心选择:在每一步,选择面值最大的硬币,只要它不超过还需要找零的金额。
  3. 更新剩余金额:从需要找零的金额中减去所选硬币的面值。
  4. 重复:重复步骤2和步骤3,直到剩余找零金额为0。
    下面是找零问题的一个简单实现:
#include <stdio.h>
// 硬币面值的数组,按从大到小的顺序排列
int coins[] = {50, 20, 10, 5, 1};
int numCoins = sizeof(coins) / sizeof(coins[0]);
// 使用贪心算法计算找零所需的最少硬币数量
void greedyChange(int amount) {int coinCount = 0; // 硬币总数for (int i = 0; i < numCoins; i++) {// 选择当前最大的硬币,只要它不超过剩余金额int coin = coins[i];int count = amount / coin; // 可以使用该硬币的数量coinCount += count;amount -= count * coin; // 更新剩余金额printf("使用面值%d元的硬币%d个\n", coin, count);}printf("总共需要%d个硬币\n", coinCount);
}
int main() {int amount;printf("请输入需要找零的金额: ");scanf("%d", &amount);greedyChange(amount);return 0;
}

在这个例子中,贪心算法能够给出最优解,因为我们假设硬币的面值是标准的,并且找零问题具有贪心选择性质,即每次选择最大面值的硬币不会影响后续选择的最优性。
贪心算法的其他例子包括:

  • 哈夫曼编码:用于数据压缩的最优前缀编码方法。
  • 图的最小生成树:例如普里姆算法(Prim’s Algorithm)和克鲁斯卡尔算法(Kruskal’s Algorithm)。
  • 图的最短路径问题:迪杰斯特拉算法(Dijkstra’s Algorithm)在某些条件下可以看作是贪心算法。
    这些例子展示了贪心算法在不同问题领域的应用,尽管在某些情况下需要额外的条件来保证贪心算法能够得到最优解。
    在这里插入图片描述

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

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

相关文章

08.SQL注入-下(超详细!!!)

1、Access注入 1.1 判断是否存在注入漏洞 ?id10 and 11 //不报错 ?id10 and 12 //报错1.2 判断字段数 ?id10 order by 1 ... ?id10 order by 7 //不报错 ?id10 order by 8 //报错 说明有7个字段1.3 猜表名 ?id10 and exists(select * from administrator) …

用队列实现栈

1 .思路及目的 用两个标准的队列&#xff08;先进先出&#xff09;实现栈&#xff08;后进先出&#xff09; 始终保持一个队列为空&#xff0c;往非空的栈插入数据 删除数据时&#xff0c;将数据导入另一个队列&#xff0c;留下最后一个数据&#xff08;这个数据就是要删除的…

各种排序算法【持续更新中.....】

1.归并排序 归并排序 &#xff0c;归并排序是采用分治法(Divide and Conquer&#xff09;的一个非常典型的应用&#xff0c;所以我们先来说一下什么是分治法。 分治法 定义 分治&#xff08;英语&#xff1a;Divide and Conquer&#xff09;&#xff0c;字面上的解释是「分…

什么情况?我代码没了

前两天检视代码时&#xff0c;发现PR里面有两个提交的描述信息一模一样&#xff0c;于是我提出应该将这两个提交合并成一个&#xff0c;保持提交树的清晰。 1 先储存起来&#xff01; 而同事这时正在开发别的特性&#xff0c;工作区不是干净的&#xff0c;没法直接执行 git r…

xss漏洞(二,xss靶场搭建以及简单利用)

本文仅作为学习参考使用&#xff0c;本文作者对任何使用本文进行渗透攻击破坏不负任何责任。 一&#xff0c;环境搭建。 使用工具&#xff1a;PHP study&#xff0c;dvwa靶场。 1&#xff0c;GitHub上下载dvwa到PHP study的WWW文件夹内&#xff0c;并解压。 dvwa下载地址 …

动态规划之——背包DP(进阶篇)

文章目录 概要说明多重背包(朴素算法)模板例题思路code 多重背包&#xff08;二进制优化&#xff09;模板例题思路code 多重背包(队列优化)模板例题思路 混合背包模板例题思路code1code2 二维费用背包模板例题思路code 概要说明 本文讲多重背包、混合背包以及二维费用背包&…

企业社会责任(CSR)国际标准有哪些?

以下是一些常见的企业社会责任&#xff08;CSR&#xff09;国际标准和相关体系等&#xff1a; 原则性、指南性标准 ISO 26000《社会责任指南》 &#xff1a;将社会责任归纳为7个核心方面&#xff0c;即公司治理、人权、劳工、环境、公平运营实践、消费者问题以及对社会发展作贡…

codetop标签双指针题目大全解析(C++解法),双指针刷穿地心!!!!!

写在前面&#xff1a;此篇博客是以[双指针总结]博客为基础的针对性训练&#xff0c;题源是codetop标签双指针近一年&#xff0c;频率由高到低 1.无重复字符的最长子串2.三数之和3.环形链表4.合并两个有序数组5.接雨水6.环形链表II7.删除链表的倒数第N个节点8.训练计划II9.最小覆…

餐饮业的数字化突围:价格战下的转型与新生

原文链接&#xff1a;https://tecdat.cn/?p37241 餐饮业价格战升级了&#xff0c;越打越激烈。近日&#xff0c;各餐饮巨头也被迫纷纷下场。 “太二酸菜鱼客单价跌至七年前” “9.9元就可以点上海底捞的一份锅底” “必胜客推出人均20元的乐享店”…… 消费降级的时代潮水&am…

dockerfile定制镜像 docker-compose编排容器

1 dockerfile dockerfile本质上是利用了Linux系统的挂载&#xff08;UnionFS&#xff09;&#xff0c;将多个目录挂载到同一目录下&#xff0c;实现镜像的层叠式结构&#xff0c;从而实现功能聚合。 1.1 一个最简单的程序 package mainimport "fmt"func main() {f…

4.Redis数据结构通用命令

Redis数据结构 Redis是一个键值对的数据库。 key&#xff1a;大多都是String value: 类型多种多样 Redis通用命令 keys :查看所有的key 不建议在生产环境上使用keys命令&#xff0c;因为redis是单线程的&#xff0c;keys命令会搜索很长一段时间&#xff0c;搜索的期间redi…

Java I/O (Input/Output)——文件字节流

博客主页&#xff1a;誓则盟约系列专栏&#xff1a;Java SE 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Java I/O 简介 Java I/O&#xff08;输入/输出&#xff09;是 Java 程序中…

[C++] 模板进阶:特化与编译链接全解析

文章目录 非类型模板类型形参非类型模板参数代码示例 **模板的特化**为什么要有模板的特化函数模板特化使用场景与示例函数模板特化的实现细节 类模板特化全特化示例 偏特化部分优化通过进一步限制模板参数进行特化偏特化为指针类型示例&#xff1a;偏特化为引用类型示例&#…

menuconfig+Kconfig的简单配置

目录 1.背景 2.管理方案 2.1&#xff1a;.h中直接定义 2.2&#xff1a;.batCmake 2.3&#xff1a;Kconfig 2.3.1 环境安装 2.3.2 代码 2.3.2.1 目录结构 2.3.2.2 ble目录下的Kconfig 2.3.2.3 hardware目录下的Kconfig 2.3.2.4 rtos目录下的Kconfig 2.3.2.5 根目录 …

申请专利需要准备哪些材料?

申请专利需要准备哪些材料&#xff1f;

实践致知第17享:电脑忽然黑屏的常见原因及处理方法

一、背景需求 小姑电话说&#xff1a;最近&#xff0c;电脑忽然就黑屏了&#xff08;如下图所示&#xff09;&#xff0c;但是等待几十秒甚至一分钟&#xff0c;电脑就能自然恢复了&#xff0c;这种状况一天能出现三四次&#xff0c;怎么办&#xff1f; 二、分析诊断 电脑黑屏…

keeplive配置详解与haproxy配置详解

一、keepalive相关知识 1.1 keepalive介绍 keepalive即LVS集群当中的高可用架构&#xff0c;只是针对调度器的高可用。是高可用的HA架构。 keepalive就是基于VRRP协议来实现LVS高可用的方案。 1、组播地址 224.0.0.18&#xff0c;根据组播地址进行通信&#xff0c;主备之间发…

Java多线程-----定时器(Timer)及其实现

目录 一.定时器简介&#xff1a; 二.定时器的构造方法与常见方法&#xff1a; 三.定时器的模拟实现&#xff1a; 思路分析&#xff1a; 代码实现&#xff1a; 在开发中&#xff0c;我们经常需要一些周期性的操作&#xff0c;例如每隔几分钟就进行某一项操作&#xff0c;这…

标准IO——文件定位、文件IO

续&#xff1a;feof、ferror&#xff08;检测一个流是否出错&#xff09;、clearerr&#xff08;清除一个流出错的标记&#xff09;。 一、标准IO文件定位 1、fseek(定位&#xff09; int fseek(FILE *stream , long offset(偏移长度) , int whence(偏移起始位置)) 其中when…

阿里云SMS服务C++ SDK编译及调试关键点记录

一. 阿里云SMS服务开通及准备工作 在阿里云官网上完成这部分的工作 1. 申请资质 个人or企业 我这里是用的企业资质 2. 申请签名 企业资质认证成功后&#xff0c;会自动赠送一个用于测试的短信签名 也可以自己再进行申请&#xff0c;需要等待审核。 3. 申请短信模板 企…