硬币找零问题,动态规划基础,百度面试题

问题描述:给出几种面值的硬币,要求用这几种硬币找零出所给零钱数,用的硬币数要最少

过去我们用过贪心法解决此类问题,包括本人在百度面试时,也是用的贪心法(面试官对这个解答不满意),贪心法只适用于硬币特殊的情况下(1,3,5),如果现在硬币的面值为10,7,3,1,要求给出21的找零方案,那么贪心会给出10,7,3,1的方案,而不是3个7块的最佳方案。

那么动态规划又该如何解决,动态规划在于在解决问题的途中用到之前的得到的答案。

思考:求n的找零方案时,可将问题分解为1-(n-1)的找零方案中加上一个已知面值的硬币,求其最小值便可。

代码如下:

#include<iostream>
using namespace std;

//三个参数依次是硬币面值数组,硬币种类,给出的零钱
void getMin(int *values,int valueKinds,int money){
    int *coinUsed = new int[money+1]();
    int *coinUsedNum = new int[money+1]();//(之前写的代码无法得出在无法找零情况下的正确答案,用这个数组不仅可以记录给出的硬币,还可以得出是否能找开的情况) 
    coinUsed[0] = 0;
    for(int cent=1;cent<=money;cent++){
        //每个零钱找零的最大值便是最小面值组成的个数 
        int minCent = cent;
        int moneyUsed = 0;
        for(int kind=0;kind<valueKinds;kind++){
            if(values[kind]<=cent){
                //所查找找零最小数为已知的零钱找零数 + 一个已有面值,便是最少硬币方案 
                int temp = coinUsed[cent - values[kind]] + 1;
                //此处应该做一个判断,即是否找得开,找不开便不必更新最小值 
                if(temp <= minCent && (cent == values[kind] || coinUsedNum[cent - values[kind]] != 0)){
                    minCent = temp;
                    moneyUsed = values[kind];
                }
            }
        }
        coinUsed[cent] = minCent;
        coinUsedNum[cent] = moneyUsed;
    }
    if(coinUsedNum[money] == 0){
        printf("面值为%d的零钱找不开!", money);
    } else {
        printf("面值为%d的最少找零数为%d,", money,coinUsed[money]);
        printf("找零面值分别为:");
        while(money>0){
            printf(" %d",coinUsedNum[money]);
            money -= coinUsedNum[money];
        }
    }
}

int main(){
    int a[5] = {2,5,10,21,25};
    int money = 24;
    getMin(a,5,money);
} 

 

posted on 2017-08-10 20:00  T~Z  阅读(531)  评论(0编辑  收藏  举报