贪心算法
贪心算法在每一步做出当前看来最优的选择,选定后不再撤回。这种策略之所以有效,并非因为“局部最优等于全局最优”(这通常是错的),而是因为特定问题的结构保证了:存在一个全局最优解,它恰好包含了这个局部选择。
设计流程
- 定义问题:明确什么是可行解,目标函数是什么(最大化还是最小化)。
- 制定规则:确定局部选择准则(Greedy Choice),并明确选择后剩余子问题的形态。
- 证明安全性:证明该局部选择是“安全”的,即它必然属于某个最优解。
- 验证子问题结构:证明剩余子问题与原问题具有相同的结构(递归性质)。
- 分析复杂度:根据选择策略和数据结构更新操作推导时间复杂度。
常见证明模式
- 交换论证 (Exchange Argument):假设存在一个最优解 与贪心解 不同。通过逐步将 中的元素替换为 中的元素,证明替换过程不会使解变差,最终 变为 。
- 保持领先 (Stays Ahead):定义一个度量指标,证明在算法执行的每一步(前缀),贪心算法的当前状态在该指标上都不劣于任何其他竞争算法。
- 割性质 (Cut Property):常用于图论。如果一条边是横跨某个割(Cut)的权重最小的边,那么这条边一定属于某个最小生成树(MST)。
- 数学归纳法:证明第一步选择安全后,假设前 步选择安全,进而证明第 步选择也安全,从而覆盖整个序列。
代表性问题
注意:贪心策略在任意实例上并不总是有效。例如,贪心找零(每次选最大面额)、追求即时利润最大化或即时成本最小化,在缺乏特定结构约束时往往会失败。一个看似合理的贪心规则,在没有证明或已知结构定理支持之前,仅仅是一个猜想。
贪心与动态规划
- 动态规划 (DP):保存可复用子问题的结果,并比较不同选择,适用于子问题重叠且贪心选择无法保证全局最优的情况。
- 贪心算法:利用“安全选择定理”直接坍缩选择空间,无需回溯。
当问题的交换性质(Exchange Property)不成立时,意味着贪心选择可能排除掉全局最优解,此时可能需要保留更多状态,用动态规划或其他适合问题的算法比较备选方案。
失败的规则留下了什么状态
面额 1、3、4 可无限使用时,大面额优先把 6 凑成 4+1+1,但 3+3 更省硬币。局部规则没有有效交换论证,却丢掉了后者:把两枚 3 换成一枚 4,余数还要两枚硬币。
动态规划保留 dp[t],表示恰好凑出 t 的最少硬币数,并考虑每种最后一枚硬币:在不超过 t 的面额 c 中取 dp[t] = min(1+dp[t-c])。初始化 dp[0]=0,不可达金额为无穷大。金额 0..6 的表为 [0,1,2,1,1,2,2]。在此正整数、无限使用模型下,目标 T、面额数 k 对应 O(Tk) 时间和 O(T) 空间。贪心失败并不意味着所有问题都必须用 DP;穷举或其他结构性算法也可能更合适。