-
题目描述:
-
有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。
如,有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
-
来源:
题目分析:
这是一个0-1背包问题,可采用动态规划来解答。这应该是07年3个题中难度最大的一个。
源代码1(略显笨拙,将dp过程存在二维数组中)
#include <stdio.h>
#include <stdlib.h>
int main()
{
int m, n;
while(scanf("%d%d", &m, &n) != EOF)
{
int value[20] = {0};
int i, j;
for(i=1; i<=n; i++)
scanf("%d", &value[i]);
int num[30][150] = {0};
for(i = 0; i <= n; i++)
for(j = 0; j <= m; j++)
{
if(j == 0)
num[i][j] = 0;
else if(i == 0)
num[i][j] = -1;
else
{
if(j < value[i])
num[i][j] = num[i-1][j];
else
{
int a = num[i-1][j];
int b = num[i-1][j-value[i]];
if(a == -1 && b == -1)
num[i][j] = -1;
else if(a >= 0 && b == -1)
num[i][j] = a;
else if(a == -1 && b >= 0)
num[i][j] = b + 1;
else
num[i][j] = a<(b+1) ? a:(b+1);
}
}
}
if(num[n][m] == -1)
num[n][m] = 0;
printf("%d\n", num[n][m]);
}
//system("pause");
return 0;
}
/**************************************************************
Problem: 1209
User: superlc320
Language: C++
Result: Accepted
Time:70 ms
Memory:1020 kb
****************************************************************/
源代码2(参考某大神的,dp过程存在一维数组中)
#include <stdio.h>
#include <stdlib.h>
#define INF 1000000000
int min(int a, int b)
{
return a < b ? a : b;
}
int main()
{
int m, n;
while(scanf("%d%d", &m, &n) != EOF)
{
int value[30] = {0};
int dp[200] = {0};
int i, j;
for(i = 0; i < n; i++)
scanf("%d", &value[i]);
for (i = 1; i <= m; i++)
dp[i] = INF;
for (i = 0; i < n; i++)
for (j = m; j >= value[i]; j--)
dp[j] = min(dp[j], dp[j-value[i]]+1);
if(dp[m] == INF)
printf("0\n");
else
printf("%d\n", dp[m]);
}
//system("pause");
return 0;
}
/**************************************************************
Problem: 1209
User: superlc320
Language: C++
Result: Accepted
Time:40 ms
Memory:1020 kb
****************************************************************/