一、贪心算法原理与实例剖析
贪心算法作为一种独具特色且应用广泛的策略,占据着重要地位。其核心策略在于将复杂的整体问题,拆解为一系列紧密相连的步骤。每一个步骤都选取当前状态下的最优方案,通过这样的方式步步推进,直至完成所有步骤。从本质而言,贪心算法在处理问题时,着重于当下的抉择,全力聚焦于当下时刻的最优选择,而暂且搁置对最终结果的预先考量。
然而,运用贪心算法时需格外留意一个关键前提:每一步所做出的选择,务必确保不会对后续步骤产生负面影响,每一步都应保持相对独立,互不干扰。
为了更为直观地理解贪心算法,我们来看一个具体例子。假设有三种面值的硬币,分别为 1 元、2 元、5 元,且每种硬币数量充足。现在要支付 M 元,目标是使用最少数量的硬币,该如何选择支付组合呢?
经简单分析,我们很容易得出局部最优策略:为使硬币数量最少,每次选择硬币时,优先挑选面值较大的。比如,当 M = 10 元时,我们会优先选择 2 个 5 元硬币,仅用 2 个硬币就完成支付。若先选小面值硬币,所需硬币数量会更多。在此例中,始终采取这种局部最优策略,最终能获得全局最优结果,即使用最少数量的硬币完成支付。
不过,并非所有问题都能通过局部最优策略轻松达成全局最优。再看另一个例子,现有四种面值的硬币,分别是 1 元、3 元、7 元、8 元,数量同样不限,要支付 M 元并使用最少数量的硬币。
假设需支付 10 元,若按先前的贪心算法,每次优先选大面值硬币,我们会先选 1 个 8 元硬币,剩余 2 元再选 2 个 1 元硬币,共需 3 个硬币,支付方式为 8 + 1 + 1 。但全面考虑所有可能组合后会发现,采用 1 个 3 元硬币和 1 个 7 元硬币的组合,即 3 + 7 ,仅需 2 个硬币就能完成支付,这才是最优方案。
为何同样是求最少硬币支付问题,结果却大相径庭?这背后与硬币面值间的关系紧密相关。在第一个例子中,5 元(大面值)> 1 元 + 2 元(小面值之和),这意味着优先选大面值硬币,不会致使后续需用更多小面值硬币来填补,从而可通过局部最优策略得到全局最优解。但在第二个例子中,8 元(大面值)< 1 元 + 3 元 + 7 元(小面值之和),这使得仅靠每次选大面值硬币的局部最优策略,无法保证获得使用最少数量硬币的全局最优解,某些情形下,先选小面值硬币的组合反而更优。
二、贪心算法的适用场景
一般而言,当问题具备以下两种特性时,便可以考虑运用贪心算法:
-
贪心选择性质:对于给定问题,若能证明在任何阶段,当下的贪心选择都不会对未来的最优解造成影响,或者说当前的最优选择是可靠的,能够通过局部最优逐步达成全局最优。
-
最优子结构性质:若问题的最优解所涵盖的子问题的解同样是最优的,我们称该问题具备最优子结构性质。即问题的最优解可由子问题的最优解组合而成,且各子问题的最优解相互独立,不会干扰其他子问题的最优解。
在 “有 1 元、3 元、7 元、8 元的四种硬币,数量不限,需要支付 M 元且要求硬币数量最少” 这个问题中,若按照贪心算法的思路,每一步都优先选择当前面值最大的硬币,局部最优选择是优先使用大面值硬币。比如当需要支付 10 元时,按照贪心策略,先选 8 元硬币,剩下 2 元再选 2 个 1 元硬币,总共使用 3 个硬币(8 + 1 + 1)。但实际上,使用 1 个 3 元硬币和 1 个 7 元硬币的组合(3 + 7),仅需 2 个硬币就能完成支付,这种非贪心选择的方式得到了更优的结果。
这表明在这个问题中,每一步的局部最优选择(优先选大面值硬币)并不能保证最终得到全局最优解(硬币数量最少),即当前的贪心选择并不能导向整体问题的最优解,所以违背了贪心选择性质。而该问题依然具有最优子结构性质,因为对于支付金额 M 元的问题,其最优解包含的子问题(如支付 M - 3 元、M - 7 元等)的解也是最优的,只是贪心选择性质的缺失导致无法直接使用贪心算法来求解。
尽管上述阐述已较为详细,但对于读者而言,可能仍稍显抽象。要解决实际的贪心问题,需要做到以下两点:
-
经验积累:积累各种不同类型的贪心问题案例。
-
反例验证:在提出贪心策略后,构造反例,通过验证来判断所构思的贪心策略是否正确。
三、例题
对于贪心问题,拥有一定的经验是至关重要的,在考场上,一般情况下没有机会去进行严格的证明,80%都是依靠感觉和经验,所以,多打怪,多升级。