1. 问题
如果硬币的面值是c0, c1, …, ck,则贪婪算法总是用最少的硬币找零
2. 证明
2.1 一个硬币的找零方式可以用如下公式来表示
m0c0 + m1c1 + … + mkck = S
mi = 每种面值的硬币的数量(0, x)
ci = 硬币的面值
根据题意 S = m0c0 + m1c1 + … + mkck
2.2 正面证明没有合适的公式推导,因为贪婪算法没有合适的公式表达,尝试反证
假设有一种非贪婪算法的最优找零方案 S1 = m0c0 + m1c1 + … + mkck
贪婪算法的找零方案 S2 = n0c0 + n1c1 + … + nkck
假设从k开始,到x(x <= k)对应的面值的硬币时,mx != nx
∵贪婪算法每次都讲尽可能的使用最大面值的硬币找零,所以nx > mx (因为S2的找零方案不同于S1,所以一定会有这么一个x满足条件)
我们考虑最小情况,nx - mx = 1
1ck = c0 + (c-1)c0 + (c-1)c1 + … + (c-1)ck-1 > (c-1)c0 + (c-1)c1 + … + (c-1)ck-1
∵S1的找零方案中,m(m < k)不可能大于或等于c(当mx > c时,就可以将c个mx换成更高位的面值了,这样硬币数会减少)
∵S1 = m0c0 + m1c1 + … + mkck-1 <= (c-1)c0 + (c-1)c1 + … + (c-1)ck-1 < 1ck
∵S1中剩下的面值小于ck的硬币面值总和不会大于一个ck的面值
∴ S1 != S2
∴ S1不存在,S2的贪婪算法是最优解
2.3 《离散数学及其应用》书中贪婪算法的反例
有面值1, 10, 25的硬币,找零30。
贪婪算法的解:5c0 + 0c1 + 1c2 = 5*1 + 0*10 + 1*25 = 30,共需6枚硬币
而最优解是:0c0 + 3c1 + 0c2 = 0*1 + 3*10 + 0*25 = 30,只需3枚硬币
因为用3枚10面值的硬币不能用任何25面值的硬币和10面值的硬币代替,所以换成高面值的硬币不一定会使硬币减少,所以2.2的证明无法在此应用
3. 扩展
从2.2的证明中可以看出,当贪婪算法是最优解时,只要cx = n*cx-1,2.2的证明同样是成立的
所以硬币的面值是k0c, k1c, …, knc时(如2, 10, 50)时,也是成立的
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架