• 九度笔记之 1209最小邮票数


    题目1209:最小邮票数

    时间限制:1 秒

    内存限制:32 兆

    特殊判题:

    提交:1176

    解决:358

    题目描述:

        有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。
        如,有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

    算法分析

    动态规划问题,和之后的两船载物、今年暑假不AC、招聘会、热爱生活(发大米)、DOTA等均为同一类型题目,背包问题。
    在该题中采用动态规划,计算从1到m面值的最小邮票数 。更新如下
    		for(int j = m;j>=num[i];j--){ //must from m to num[i]
    			dp[j] = std::min(dp[j],dp[j-num[i]]+1);
    		}
    表示在第i个邮票加入后,从m值到num[i]值的最小邮票数,一定要从m到num[i],由多到少,因为邮票的数量是固定的。
    因为更新时
    std::min(dp[j],dp[j-num[i]]+1);
    min里面的dp[ j ],  dp[ j-num[i] ]都是只有前i-1个邮票的情况下组成的最小数,如果从num[i]开始更新,那么随着i增加到后面dp[ j-num[i] ]表示的就是前i个邮票的情况下组成的最小数,再+1,第i个邮票就重复了。

    如果是从num[i]到m更新,表示不同面值邮票数是无限的,具体会在以后相关的算法问题中说明。(DOTA问题)
    std::min(dp[j],dp[j-num[i]]+1);
    当前的最小数 是 j总值下前i-1个邮票所能组成的最小数, j-num[i]总值前i-1个邮票所能组成的最小数+1  的最小值,也就是前i-1个邮票的最小个数和包含第i个邮票的最小个数的最小值。

    源程序

    //============================================================================
    // Name        : judo1209.cpp
    // Author      : wdy
    // Version     :
    // Copyright   : Your copyright notice
    // Description : Hello World in C++, Ansi-style
    //============================================================================
     
    #include <iostream>
    #include <cmath>
    using namespace std;
    int INF = 1<<30;
    void minNum(int m,int n){
        int *dp = new int[m+1];
        dp[0] = 0;
        for(int i = 1;i<=m;i++)
            dp[i] = INF;
        int *num = new int[n];
        for(int i = 0;i<n;i++)
            std::cin>>num[i];
        for(int i = 0;i<n;i++){
            for(int j = m;j>=num[i];j--){ //must from m to num[i]
                dp[j] = std::min(dp[j],dp[j-num[i]]+1);
            }
        }
        if(dp[m]<INF)
            std::cout<<dp[m]<<std::endl;
        else
            std::cout<<0<<std::endl;
    }
    void minNumnew(int m,int n){
        int *dp = new int[m+1];
        dp[0] = 0;
        for(int i = 1;i<=m;i++)
            dp[i] = INF;
     
        int num;
        for(int i = 0;i<n;i++){
            std::cin>>num;
            for(int j = m;j>=num;j--){ //must from m to num[i]
                dp[j] = std::min(dp[j],dp[j-num]+1);
            }
        }
        if(dp[m]<INF)
            std::cout<<dp[m]<<std::endl;
        else
            std::cout<<0<<std::endl;
    }
    void judo(){
        int m = 0;
        int n = 0;
        while(std::cin>>m>>n){
            minNumnew(m,n);
        }
    }
     
    int main() {
         judo();
        return 0;
    }
    /**************************************************************
        Problem: 1209
        User: KES
        Language: C++
        Result: Accepted
        Time:160 ms
        Memory:3632 kb
    ****************************************************************/




  • 相关阅读:
    【Python3 爬虫】U31_selenium定位元素
    【Python3 爬虫】U30_selenium初识
    verilog语法实例学习(1)
    verilog语法学习目录
    在testbench从文件读入激励
    Verilog 加法器和减法器(7)
    浮点数的表示和运算
    Verilog 加法器和减法器(6)
    Verilog 加法器和减法器(5)
    Verilog 加法器和减法器(4)
  • 原文地址:https://www.cnblogs.com/aukle/p/3221827.html
Copyright © 2020-2023  润新知