题目描述
有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。 如,有1分,3分,3分,3分,4分五张邮票,要求凑成10分,则使用3张邮票:3分、3分、4分即可。
输入描述
有多组数据,对于每组数据,首先是要求凑成的邮票总值M,M<100。然后是一个数N,N〈20,表示有N张邮票。接下来是N个正整数,分别表示这N张邮票的面值,且以升序排列。
输出描述
对于每组数据,能够凑成总值M的最少邮票张数。若无解,输出0
示例
输入
10
5
1 3 3 3 4
输出
3
思路
dfs或者动态规划
实现
实现1:dfs
#include<bits/stdc++.h>
using namespace std;
void dfs(int m,int den[],int start,int cnt,int& min)
{
if(m == 0)
{
if(cnt < min) min = cnt;
return;
}
for(int i = start;i >= 0;i--)
{
if(m >= den[i]) dfs(m-den[i],den,i-1,cnt+1,min);
}
}
int main()
{
int m;
while(cin >> m)
{
int min = 21;
int n;
cin >> n;
int den[n];
for(int i = 0;i < n;i++) cin >> den[i];
dfs(m,den,n-1,0,min);
if(min == 21) cout << 0 << endl;
else cout << min << endl;
}
return 0;
}
实现2:动态规划
状态转移方程为:dp[j] = min(dp[j],dp[j - den[i]]+1)
,这个解法我搞不太懂...
#include<bits/stdc++.h>
using namespace std;
int MIN(int a,int b)
{
return a < b? a:b;
}
int main()
{
int m;
while(cin >> m)
{
int dp[101];
for(int i = 1;i < 102;i++) dp[i] = INT_MAX;
dp[0] = 0;
int min = 21;
int n;
cin >> n;
int den[n];
for(int i = 0;i < n;i++) cin >> den[i];
for(int i = 0;i < n;i++)
{
for(int j = m;j >= den[i];j--)
{
if(dp[j - den[i]] != INT_MAX) dp[j] = MIN(dp[j],dp[j - den[i]]+1);
}
}
if(dp[m] == INT_MAX) cout << 0 << endl;
else cout << dp[m] << endl;
}
return 0;
}