入门题集----01----最少钱币数

最少钱币数:

【问题描述】

这是一个古老而又经典的问题。用给定的几种钱币凑成某个钱数,一般而言有多种方式。例如:给定了6种钱币面值为2、5、10、20、50、100,用来凑 15元,可以用5个2元、1个5元,或者3个5元,或者1个5元、1个10元,等等。显然,最少需要2个钱币才能凑成15元。

你的任务就是,给定若干个互不相同的钱币面值,编程计算,最少需要多少个钱币才能凑成某个给出的钱数。

要求

数据输入】输入可以有多个测试用例。每个测试用例的第一行是待凑的钱数值M(1 <= M<= 2000,整数),接着的一行中,第一个整数K(1 <= K<= 10)表示币种个数,随后是K个互不相同的钱币面值Ki(1 <= Ki <= 1000)。输入M=0时结束。

数据输出】每个测试用例输出一行,即凑成钱数值M最少需要的钱币个数。如果凑钱失败,输出“Impossible”。你可以假设,每种待凑钱币的数量是无限多的。

样例输入

15

6 2 5 10 20 50 100

1

1 2

0

样例输出

2

Impossible

/*上来感觉是个贪心,实则不是,贪心得到的近似解不是最优,如有10 7 2 时,要想得到14元,贪心的答案是3,

即:14=10*1+2*4,但是应为2时最少,即:14=7*2    */

惊了!!!有个算法好像可以算出对的哎!!!

何dalao说是树状dp orz

#include <iostream>
using namespace std;
int _min,q[10];
void money(int n,int p,int c){
    if(p<0){
        return;
    }
    if(c<_min&&n==0){
        _min=c;
    }
    if(n>=q[p]){
        money(n-q[p],p,++c);
        --c;
        money(n,--p,c);
        ++p;
    }else if(n>0){
        money(n,--p,c);
        ++p;
    }
    return ;
}
int main()
{
    int m,k;
    while(cin>>m&&m!=0){
        _min=9999;
        cin>>k;
        for(int i=0;i<k;i++){
            cin>>q[i];
        }
        money(m,k-1,0);
        if(_min!=9999){
            cout<<_min<<endl;
        }else{
            cout<<"Impossible"<<endl;
        }
    }
    return 0;
}

摘抄:https://blog.csdn.net/G7S9R/article/details/78461181点击打开链接

dp的思路 :

采用动态规划的思想来解此题。首先设定dp[i][j]数组,i的意思是当前的最大货币数,j的意思是目标货币数。因此dp[i][j]的意思就是使用最大货币i可以组成货币j的最少货币数。假设现在有{10,5,2,1}的货币,要求找出15元。当手里有1元时,无法找出15元,但是当最大的货币数为5元时,可以有5+5+5这一种情况,货币数最少为3.

设此时的dp[i][j]为MaxValue(Integer所能表示的最大值)。依次遍历每一种货币值和目标钱数。其中有一个重要的公式:

dp[i][j] = min{dp[i-1][j],dp[i][j-amount]+1};

即当前手里的货币值最大的为i时,目标金额减去i的数值amount,计算最大为i求定额j-amount的数目。该值之前曾计算出来。注意需要在最终解上+1。同时还要和i-1情况下的货币值(也可以组成目标j的货币值)做一个对比,取最小值。

public int Solution(int [] coins,int aim){
        if(coins == null || aim<=0)
            return 0;
        //动态规划数组
        int [][] dp = new int [coins.length][aim+1];
        int maxvalue = Integer.MAX_VALUE;

        //初始化dp数组
        for(int i=1;i<=aim;i++){
            dp[0][i] = maxvalue;
            if(i>=coins[0] && dp[0][i-coins[0]] != maxvalue){
                dp[0][i] = dp[0][i-coins[0]]+1;
            }
        }

        //计算每个数组所需的最小货币数
        int left = 0;
        for(int i=1;i<coins.length;i++){
            for(int j=1;j<aim+1;j++){
                left = maxvalue;
                if(j>=coins[i]&& dp[i][j-coins[i]] != maxvalue){
                    left = dp[i][j-coins[i]]+1;
                }
                dp[i][j] = left<dp[i-1][j]?left:dp[i-1][j];
            }
        }
        return dp[coins.length-1][aim];
    }

猜你喜欢

转载自blog.csdn.net/DorisBao1021/article/details/81065212