当前位置:编程学习 > 网站相关 >>

九度笔记之 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面值的最小邮票数 。更新如下

[cpp]
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); 

  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],由多到少,因为邮票的数量是固定的。
因为更新时
[cpp]
std::min(dp[j],dp[j-num[i]]+1); 

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问题)
[cpp]
std::min(dp[j],dp[j-num[i]]+1); 

std::min(dp[j],dp[j-num[i]]+1);当前的最小数 是j总值下前i-1个邮票所能组成的最小数,j-num[i]总值前i-1个邮票所能组成的最小数+1  的最小值,也就是前i-1个邮票的最小个数和包含第i个邮票的最小个数的最小值。
源程序
[cpp]
//============================================================================  
// 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
****************************************************************/ 

//============================================================================
// 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);
     &n

补充:综合编程 , 其他综合 ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,