动态规划-找零钱问题
从贪心说起
我们知道贪心算法可以解决「硬币找零问题」,但是那只是在部分情况下可以解决而已。
那么有什么情况下不能用贪心算法吗?比如一个算法星球的央行发行了奇葩币,币值分别为{1、5、11},要凑够15元,这个时候贪心算法就失效了。
按照贪心算法的策略,我们先拿出最大面值的11,剩下的4个分别对应四个1元的奇葩币,这总共需要五个奇葩币才能凑够15元。
而实际上我们简单一算,就知道最少情况是拿出3个五元的奇葩币才能凑够15元
动态规划
我们要凑够这个 n,只要 n 不为0,那么总会有处在最后一个的硬币,这个硬币恰好凑成了 n
- 假设最后一个硬币为11的话,那么剩下4(15-11),这个时候问题又变成了,我们凑出 n-11 最少需要多少个币
- 如果假设最后一个硬币为 5 的话,这个时候问题又变成了,我们用现有的币值凑出 n-5 最少需要多少个币
我们的问题提可以不断被分解为「我们用现有的币值凑出 n 最少需要多少个币」,用 f(n) 函数代表 「凑出 n 最少需要多少个币」.
把「原有的大问题逐渐分解成类似的但是规模更小的子问题」这就是最优子结构,我们可以通过自底向上的方式递归地从子问题的最优解逐步构造出整个问题的最优解。
这个时候我们分别假设 1、5、11 三种面值的币分别为最后一个硬币的情况:
- 最后一枚硬币的面额为 11: min = f(4) + 1
- 最后一枚硬币的面额为 5: min = f(10) + 1
- 最后一枚硬币的面额为 1: min = f(14) + 1
假设凑的硬币总额为 n,那么 f(4) = f(n-11)、f(10) = f(n-5)、f(14) = f(n-1),我们得出以下公式:
再具体到上面公式中 f(n-1) 凑够它的最小硬币数量是多少,是不是又变成下面这个公式:
代码实现
# 面额:1,5,11 amount:15 (n) def f(n): res = float('INF') if n ==0: return 0 if n>=1: res = min(f(n-1)+1,res) if n>=5: res = min(f(n-5)+1,res) if n>=11: res = min(f(n-11)+1,res) return res
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)