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