问题描述:给出几种面值的硬币,要求用这几种硬币找零出所给零钱数,用的硬币数要最少。
过去我们用过贪心法解决此类问题,包括本人在百度面试时,也是用的贪心法(面试官对这个解答不满意),贪心法只适用于硬币特殊的情况下(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); }