硬币问题_动态规划

本文探讨了如何利用动态规划解决硬币找零问题,揭示了贪心策略在特定情况下的不足,并通过递推公式和代码实例展示了最优子结构和无后效性的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

硬币问题

现有若干枚硬币,硬币面值分别为1,5,11.要凑出价值为w,至少需要多少枚硬币。比如说w=15.
如果按照贪心的思维:
我们每次选取面值最大的硬币去尝试,
15 = 1 ∗ 11 + 4 ∗ 1 15=1*11+4*1 15=111+41
所以,凑出价值w=15,至少需要的硬币数为1+4=5枚。
但是,实际上我们只需要取3枚面值为5的硬币,就可以搞定。所以,此题,贪心思维,不靠谱!

分析

记凑出价值n所需要的最少硬币数为 f ( n ) f(n) f(n)
那么可以得到下面这个表:
在这里插入图片描述
可见 f ( n ) f(n) f(n)只与 f ( n − 1 ) , f ( n − 5 ) , f ( n − 11 ) f(n-1),f(n-5),f(n-11) f(n1)f(n5)f(n11)有关。
f ( n ) = min ⁡ { 1 + f ( n − 1 ) , 1 + f ( n − 5 ) , 1 + f ( n − 11 ) } f(n)=\min\{1+f(n-1),1+f(n-5),1+f(n-11)\} f(n)=min{1+f(n1),1+f(n5),1+f(n11)}

总结

  1. 最优子结构
    大问题的最优解可以由小问题的最优解推出
  2. 无后效性
    一旦 f ( n ) f(n) f(n)确定,那么之后直接调用它的值就可以,不需要再去关心 f ( n ) f(n) f(n)的计算过程。

代码

#include<iostream>
#include<string.h>
using namespace std;
const int INF = 0x3f3f3f3f;
#define W 15
#define m 3
int dp[W + 1]; // 存放最少硬币个数信息
int S[W + 1]; // 存放硬币的面值信息
int main() {
    int c[m] = {1, 5, 11};
    memset(dp, INF, sizeof(dp));
    dp[0] = 0;
    for (int w = 1; w <= W;++w) {
        for (int i = 0; i < m;++i) {
            if(c[i]<=w && dp[w]>(1+dp[w-c[i]])){
                dp[w] = 1 + dp[w - c[i]];
                S[w] = i;
            }
        }
    }
    for (int i = 0; i < W;++i) {
        cout << dp[i] << " ";
    }
    cout << endl;
    for (int i = 0; i < W;++i) {
        cout << S[i] << " ";
    }
    cout << endl;
    cout << dp[W] << endl; // 最少硬币数
    int n = W;
    while(n>0) {
        cout << c[S[n]] << " "; // 输出是哪些硬币
        n = n - c[S[n]];
    }
    system("pause");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值