描述
题目描述
有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。 如,有1分,3分,3分,3分,4分五张邮票,要求凑成10分,则使用3张邮票:3分、3分、4分即可。
输入描述:
有多组数据,对于每组数据,首先是要求凑成的邮票总值M,M<100。然后是一个数N,N〈20,表示有N张邮票。接下来是N个正整数,分别表示这N张邮票的面值,且以升序排列。
输出描述:
对于每组数据,能够凑成总值M的最少邮票张数。若无解,输出0。
示例1
输入
10
5
1 3 3 3 4
输出
3
分析
类似与找硬币的问题,可以用贪心做,但更保险的方式是用动态规划做。
令dp[i]表示凑齐面额为i的面值需要的最少的邮票数;那么这可以转化为一道01背包的问题;
dp[i] = min{dp[i],dp[i-x]+1}相当于每次增加的体积都是1,若是不选当前这个邮票,就还是dp[i];选的话就是减掉这个面值的数量加上新选的这1张
由于要刚好凑齐,而且是取最小,所以得初始化为很大的数
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
int dp[105];
int main()
{
int m, n;
while (cin>>m>>n)
{
for (int i = 0; i <= m; i++)dp[i] = 100000000;
dp[0] = 0; int x;
for (int i = 1; i <= n; i++)
{
cin >> x;
for (int j = m; j >= x; j--)
{
if (dp[j] > dp[j - x] + 1)dp[j] = dp[j - x] + 1;
}
}
if (dp[m] == 100000000)dp[m] = 0;
cout << dp[m] << "\n";
}
}