题目分析
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
n≤10,
w
≤
100
w\le 100
w≤100;
对于
100
%
100\%
100% 的数据,满足
1
≤
n
≤
1
0
3
1\le n\le 10^3
1≤n≤103,
1
≤
a
i
,
w
≤
1
0
4
1\le a_i , w\le 10^4
1≤ai,w≤104。
很显然,这道题得用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[i−a[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[i−a[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~

845

被折叠的 条评论
为什么被折叠?



