贪心贪婪算法示例

贪心贪婪算法(greedy algorithm)是计算机科学和优化的基本方法。它是一种简单直观的策略,用于解决各种问题并做出一系列选择以得出最佳解决方案。

本质上,贪心算法在每一步都会做出局部最优选择,希望这些选择能够产生全局最优解。

换句话说,它在当前情况下做出最好的决定,而不考虑未来可能的后果。以下是贪婪算法如何工作的概述:

  1. 初始化:从一个空的或琐碎的初始解决方案开始。
  2. 选择:在每个阶段,根据特定标准选择最佳可用选项。这个选择是基于目前的情况,没有考虑整个问题。
  3. 可行性:检查所选选项是否可行。如果有,将其添加到溶液中;丢弃它。
  4. 终止:重复步骤2和3,直到满足终止条件。此条件可以是达到所需解决方案的质量或彻底评估所有替代方案。
  5. 解决方案:最后,所选择的选项形成问题的解决方案。需要注意的是,虽然贪心算法很容易实现并且可能对某些问题有效,但它并不能保证所有问题的最优解决方案。

在某些情况下,贪心方法可能会导致次优结果,但在其他情况下,它可能会找到全局最优解。选择标准("贪婪选择")对算法的成功至关重要。标准的选择必须符合问题的特点,并确保每个阶段的选择都能对整体解决方案产生积极影响。

可以使用贪婪算法解决的问题包括:

  • 硬币交换问题(最小化给定数量的硬币数量)。
  • 破背包问题(最大化容量有限的背包中物品的价值)。
  • 哈夫曼编码(高效数据压缩)。

贪心算法是一种功能强大、用途广泛的工具。然而,了解它的局限性并仔细分析问题对于确定贪心算法是否合适并可能产生预期结果非常重要。

贪心算法的历史
贪心算法的概念在各个领域都有悠久的历史,可以以某种形式追溯到古代。虽然 "贪心算法 "一词可能没有被明确使用过,但几个世纪以来,做出局部最优选择的原则一直被应用于解决问题。以下是简要的历史概述:

  • 古代数学与掷硬币:贪心算法最早的应用是抛硬币问题。古代文明需要交换商品和服务,他们面临的挑战是用尽可能少的硬币来找零。这个问题可以通过一个简单的贪婪策略来解决,即总是选择不大于剩余可兑换金额的最大货币面额。
  • 哈夫曼编码贪心算法最著名的应用之一是数据压缩,特别是使用哈夫曼编码。哈夫曼于 1952 年提出。赫夫曼编码以最小化的方式为字符编码创建最优前缀二叉树。表示所需的比特总数。该算法通过在每一步中组合两个频率最低的符号来重复构建树,这是贪婪选择的一个明显例子。
  • 图论自 20 世纪中期以来,贪心算法一直被应用于图论问题。其中一个著名的例子是普里姆算法(Prim's algorithm),用于寻找图的最小生成树。该算法从单个顶点开始,迭代添加与现有树相关的最低权重边。这种贪婪的方法确保最终结果至少是一棵配置树。Dijkstra 算法:另一个重要贡献是 Edsger W. Dijkstra 于 1959 年发表的用于查找图中最短路径的 Dijkstra 算法。该算法保留了一组已知与源头距离最短的顶点,并不断扩大这组顶点,以最小化当前已知到每个顶点的距离,这代表了每一步的贪婪选择。
  • 活动选择问题:这一经典问题涉及从给定集合中选择最大的一组相互兼容的活动,每个活动都有一个开始和结束时间。该问题的贪婪算法是根据活动的结束时间对其进行排序,并在选择时避免活动重叠。

在计算机科学和各个领域的发展过程中,贪心算法已被证明是解决优化任务的一种有价值且通常直观的技术。这为许多应用领域开发高效算法铺平了道路。

贪心算法的一些例子
问题一:
给您一系列硬币(例如,1 美分、5 美分、10 美分、25 美分)和一个以美分为单位的目标。找出达到目标金额所需的最少硬币数量。
贪婪访问:

  1. 从小于或等于目标金额的最大值开始。
  2. 如果目标金额大于 0,则继续从目标金额中减去该面额的最大可能倍数。
  3. 移动到下一个较小的面额并重复该过程,直到目标金额为 0。

例子:
假设我们有面值的硬币:1 美分、5 美分、10 美分和 25 美分,我们想兑换 63 美分。
贪心解:

  1. 从最大的值 25 美分开始。我们可以使用 25 美分中的 2 个,这样就剩下 13 美分的零钱了。
  2. 下一个最大的值,10 美分,可以使用一次,剩下 3 美分。
  3. 剩余金额小于最小值5分,所以我们用三个1分来完成兑换。

结果:
制作 63 美分的最低金额是 6 个硬币(两个 25 美分、一个 10 美分和三个 1 美分)。需要注意的是,贪心算法仅有时适用于所有优化问题,并且可能无法在所有情况下找到全局最优解。

对于某些问题,例如抛硬币问题,贪婪选择属性成立(即,在每一步中做出局部最优选择会导致全局最优解),贪婪方法效果很好并提供了有效的解决方案。


问题2:
您将获得一系列任务,每个任务都有开始和结束时间。目标是选择可以完成的最大数量的非重叠任务。
贪婪访问:

  1. 按截止日期升序对任务进行排序。
  2. 滚动浏览已排序的任务列表,然后选择截止日期最早且与之前选择的任务不重叠的任务。

例子:
让我们来完成以下带有开始和结束时间的任务。
任务1:(开始时间:1,结束时间:4)
任务2:(开始时间:3,结束时间:5)
任务3:(开始时间:0,结束时间:6)
任务4:(开始时间:5,结束时间:7)
任务5:(开始时间:3,结束时间:9)
任务6:(开始时间:5,结束时间:9)
任务7:(开始时间:6,结束时间:10)

贪心解:

  1. 按截止日期升序对任务进行排序:任务 1、任务 2、任务 5、任务 3、任务 4、任务 6、任务 7。
  2. 从任务 1 开始(最早完成时间:4)。转到任务 5(任务 1 之后最早完成时间:9),因为任务 2 与任务 1 重叠。
  3. 转到任务 7(任务 5 之后最早完成时间:10),因为任务 3 和 4 与任务 1 和 5 重叠。

结果:
最多可以完成 3 个不重叠的任务,选定的任务是任务 1、任务 5 和任务 7。区间调度问题的贪心算法之所以有效,是因为选择完成时间最早的任务可以确保其他任务有更多的时间。任务。通过重复选择与之前选择的任务不重合的最早完成时间的任务,我们可以找到该问题的最优解。


问题3:
你会得到一套物品,每件物品都有重量和价值,以及一个承载能力最大的背包。目标是让背包装满物品以最大化总价值。与经典的 0/1 背包问题不同,你仍然可以拾取一些物品。

贪婪访问:

  1. 计算每种产品的价值与重量比(价值除以重量)。
  2. 按价值与重量的比例降序对产品进行排序。
  3. 按照排名列表的顺序将物品添加到背包中,直到背包满为止。

如果某件物品不太合适,请将其取出一部分以填充剩余容量。

例子:
假设您有以下具有重量和价值的物品:
项目 1.(重量:10,价值:60)
商品 2:(重量:20,价值:100)
商品 3:(重量:30,价值:120)
背包的最大承载量为50。

贪心解:

  1. 计算价值与重量之比。
  2. 按价值与重量比降序排列产品:商品 1、商品 2、商品 3。
  3. 将物品添加到您的背包中。
  4. 获取完整物品 1(重量:10,价值:60)。
  5. 剩余容量:50 - 10 = 40。
  6. 取出适合剩余容量的第 2 项(重量:20,价值:100)的 40%。剩余容量:40 - 40% * 20 = 32。
  7. 剩余容量中没有点 3 适合 (30 > 32),因此我们在此停止。

结果:
背包装满部分物品得到的最大总价值为60(从1开始)40%*100(从2开始)= 60 40 = 100。
分数背包问题的贪心算法之所以有效,是因为它专注于选择具有最高价值重量比的物品,确保尽可能多地包含最有价值的物品,即使是分数形式(如有必要)。