刷题链接
最小邮票数
题目描述
有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。 如,有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
在大佬的眼里,这又该是一道水题了,奈何博主智商着急,水了大半年才水出来。
显然这道题可以用递归来做,但是让我蛋疼的是那个回溯搞半天都不知道怎么写。无奈看了下大神的题解,然后有所领会自己又写了一遍。
邮票面额已经排好顺序,从最后那张面额最大的邮票往前开始遍历,当面额相加超过目标面额的邮票记得要回溯。整体思路大概就是这样,下面直接附上题解代码:
#include <stdio.h>
int arr[25];
int stamp_min; //最少邮票数
/*
max:当前面值最大的邮票序列
sum:当前使用的邮票数量
dest:凑成目标面额的邮票
*/
void dfs(int max, int sum, int dest)
{
if (max<0 || dest<0)
{
return;
}
//最小邮票数的判定
if (dest == 0 && stamp_min>sum)
{
stamp_min = sum;
return;
}
int i;
//想了半天的回溯
for (i=max; i>=0; i--)
dfs(i-1, sum+1, dest-arr[i]);
}
int main(int argc, const char *argv[])
{
int m;
while (~scanf("%d", &m))
{
int n, i, j;
scanf("%d", &n);
for (i=0; i<n; i++)
scanf("%d", &arr[i]);
stamp_min = 1000000; //一定记得附一个尽可能大的初值
dfs(n-1, 0, m);
if (stamp_min != 1000000)
printf("%d\n", stamp_min);
else
printf("0\n");
}
return 0;
}