每日一题之清华考研机试——最小邮票数

刷题链接
最小邮票数

题目描述
有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。 如,有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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值