洛谷 P2842 纸币问题1 题解

题目分析

题目传送门

P2842 纸币问题 1

题目描述

某国有 n n n 种纸币,每种纸币面额为 a i a_i ai 并且有无限张,现在要凑出 w w w 的金额,试问最少用多少张纸币可以凑出来?(保证可以凑出对应金额)

输入格式

第一行两个整数 n , w n,w n,w,分别表示纸币的种数和要凑出的金额。
第二行一行 n n n 个以空格隔开的整数 a 1 , a 2 , a 3 , … a n a_1, a_2, a_3, \dots a_n a1,a2,a3,an 依次表示这 n n n 种纸币的面额。

输出格式

一行一个整数,表示最少使用的纸币张数。

输入输出样例 #1

输入 #1

6 15
1 5 10 20 50 100

输出 #1

2

输入输出样例 #2

输入 #2

3 15
1 5 11

输出 #2

3

说明/提示

对于 40 % 40\% 40% 的数据,满足 n ≤ 10 n\le 10 n10 w ≤ 100 w\le 100 w100
对于 100 % 100\% 100% 的数据,满足 1 ≤ n ≤ 1 0 3 1\le n\le 10^3 1n103 1 ≤ a i , w ≤ 1 0 4 1\le a_i , w\le 10^4 1ai,w104

很显然,这道题得用dp
那么先来定义一个状态,在这道题里,要求的是用最少纸币数凑出w,所以状态需要表示出最终答案,那么状态就是: d p [ i ] dp[i] dp[i]为用给定面值凑出 i 的最少纸币数

状态转移方程

有了状态,就要来推状态转移方程
很显然, d p [ i ] dp[i] dp[i]只跟 d p [ i − a [ j ] ] dp[i-a[j]] dp[ia[j]]有关(a[j]为给定面值中的任意一个面值)
因为要凑出 i 这个面值,肯定要用给定面值凑出来,那么只需要用 i 减去一个给定面值后的面值的最少纸币数,再加一张减掉的面值的纸币,就能得到 i 的最少纸币数的一种情况,再对这些情况取个最小的,就是答案
(有点乱,不好意思尽力了)

所以,状态转移方程就为: d p [ i ] = m i n ( d p [ i − a [ j ] ] + 1 , d p [ i ] ) dp[i]=min(dp[i-a[j]]+1,dp[i]) dp[i]=min(dp[ia[j]]+1,dp[i])

程序实现

好了,状态和状态转移方程都有了,万事俱备,只欠代码!

#include <iostream>
#include <string.h> //memset初始化函数头文件
using namespace std;
int n,w;
int a[1005];
int dp[10005];  //dp[i]为用给定面值凑出i的最少纸币数
int main(){
    cin>>n>>w;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    memset(dp,0x3f,sizeof(dp));  //初始化为无穷大
    dp[0]=0;   //凑出0面值不需要纸币
    for(int i=1;i<=w;i++){
        for(int j=1;j<=n;j++){
            if(i-a[j]>=0){   //防止下标为负数
                dp[i]=min(dp[i-a[j]]+1,dp[i]);  //状态转移方程
            }
        }
    }
    cout<<dp[w];  //输出题目要求答案

    return 0;
}

亲测可AC~
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值