优快云每日一练——硬币划分

本文介绍了一种使用动态规划解决完全背包问题的方法,具体为计算组成特定金额的不同硬币组合数量。通过逐步解析动态规划的基本步骤,包括定义状态、状态转移方程及初始化条件等,给出了一段C++代码实现。

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

题目

有1分,2分,5分,10分四种硬币,每种硬币数量无限,给定n分钱(n<100000),有多少中组合可以组成n分钱?

输入描述

输入整数n.(1<=n<=100000)

输出描述

输出组合数,答案对1e9+7取模。

这是完全背包问题和背包方案数量问题的组合,这两个问题是非常经典的问题,感兴趣的可以了解一下(博主也会尽快写出来的)。掌握了常见的背包问题模型,对动态规划的理解会更进一步。

动态规划方法

动态规划做题步骤:

1.明确dp[i]表示什么

2.根据dp[i]和dp[i-1]的关系得出状态转移方程

3.确定初始条件

使用dp[i][j]表示前i中面值的硬币构成面值为j的方案的数量,c_{i}表示第i种硬币的面值。可以推导出状态转移方程: 

dp[i][j]=dp[i-1][j-0*c_{i}]+dp[i-1][j-1*c_{i}]+...+dp[i-1][j-k*c_{i}]    (k为满足j-k*c_{i}>=0的最大整数)

优化:

dp[i][j]=dp[i-1][j]+dp[i-1][j-1*c_{i}]+...+dp[i-1][j-k*c_{i}

用j-c_{i}替换j得到:dp[i][j-c_{i}]=dp[i-1][j-1*c_{i}]+...+dp[i-1][j-k*c_{i}

化简得到:dp[i][j]=dp[i-1][j]+dp[i][j-c_{i}]

现在使用的是二维数组,但是dp[i][j]=dp[i-1][j]+dp[i][j-c_{i}],更新dp只需要用到第i行和i-1行,所以可以用滚动数组来进行优化,用一个一维数组DP[n]表示在计算第i轮之前DP数组中存放着i-1轮的答案。

时间复杂度:O(N)

空间复杂度:O(N)

#include <iostream>
#include <string>
#include <sstream>
#include <vector>

using namespace std;

int solution(int n){
    int result;
    // TODO:
    int mod=1e9+7;
    int coins[4]={10,5,2,1};
    vector<int> dp(n+1);
    dp[0]=1;
    for(int i=0;i<4;++i){
        int coin=coins[i];
        for(int j=coin;j<=n;++j){
            dp[j]=(dp[j]+dp[j-coin])%mod;
        }
    }
    result=dp[n];
    return result;
}

int main() {

    int n;

    std::cin>>n;

    int result = solution(n);

    std::cout<<result<<std::endl;

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yjf~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值