题目描述
有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。 如,有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
//每张邮票价值为1,求背包容量M,N个物品,装满的前提下获得最小的价值;
//对于dp[i][j]来说,
//(1)如果放入第i个物品可以填满j容量的背包,那么使用前i-1个物品可以填满j-w[i]容量的背包,于是dp[i][j]=dp[i-1][j-w[i]]+1;
//(2)如果不放入第i个物品也可以填满j容量的背包,意味着只使用前i-1个物品仍然可以填满j容量的背包,dp[i][j]=dp[i-1][j]。
//总结以上两种情况:dp[i][j]取其中较小的。
//如果前i个物品不能存满背包,设置dp[i][j]为一个超过总价值的数,当更大的i,j需要使用较小的i,j的dp时,dp都不能存满背包,则较大的dp也不能存满背包。
//边界条件:dp[0][j]=MAX,不存放物品时,任何非零容量都不能存满;dp[i][0]=0,容量为0,总是可以填满且总价值为0;
//状态转移:dp[i][j]=min(dp[i-1][j-w[i]]+1,dp[i-1][j]);任何情况下,dp都不会超过设置的max值。
//优化:可以看到dp[i][j]只和上一行的数据有关,简化成dp[j]=min(dp[j-w[i]]+1,dp[j]),且遍历到dp[j]时,dp[j-w[i]]值应还未修改,所以j从后向前遍历。
#include<iostream>
using namespace std;
int main()
{
int w[101],dp[101];
int m,n;
while(cin>>m>>n)
{
for(int i=0;i<n;i++)
cin>>w[i];
for(int i=0;i<=m;i++) dp[i]=100000;
dp[0]=0;
for(int i=0;i<n;i++)
for(int j=m;j>=0;j--)
{
if(j>=w[i])
dp[j]=min(dp[j],dp[j-w[i]]+1);
}
if(dp[m]==100000)
cout<<0<<endl;
else
cout<<dp[m]<<endl;
}
return 0;
}