动态规划把问题分为子为题,解决了这些子问题,再把子问题合并起来,便可以得到问题的解。在解决子问题过程中,需要把子问题的解保存起来方便后面使用。
最少硬币找零问题为:给予不同面值的硬币若干种种(每种硬币个数无限多),用若干种硬币组合为某种面额的钱,使硬币的的个数最少。
在现实生活中,我们往往使用的是贪心算法,比如找零时需要13元,我们先找10元,再找2元,再找1元。这是因为现实生活中的硬币(纸币)种类特殊。如果我们的零钱可用的有1、2、5、9、10。我们找零18元时,贪心算法的策略是:10+5+2+1,四种,但是明明可以用两个9元的啊。
所以可以使用动态规划,找零18元时,我们首先找18-1=17,18-2=15,18-5,=13,18-9,=9,18-10=8;再找17-1……。这样递归解决子问题
- #include<iostream>
- using namespace std;
- //money需要找零的钱
- //coin可用的硬币
- //硬币种类
- void FindMin(int money,int *coin, int n)
- {
- int *coinNum=new int[money+1]();//存储1...money找零最少需要的硬币的个数
- int *coinValue=new int[money+1]();//最后加入的硬币,方便后面输出是哪几个硬币
- coinNum[0]=0;
- for(int i=1;i<=money;i++)
- {
- int minNum=i;//i面值钱,需要最少硬币个数
- int usedMoney=0;//这次找零,在原来的基础上需要的硬币
- for(int j=0;j<n;j++)
- {
- if(i>=coin[j])//找零的钱大于这个硬币的面值
- {
- //if(coinNum[i-coin[j]]+1<=minNum)//所需硬币个数减少了
- /*
- 上面的判断语句有问题,在更新时,需要判断i-coin[j]是否能找的开,如果找不开,就不需要更新。
- 多谢zywscq 指正
- */
- if(coinNum[i-coin[j]]+1<=minNum&&(i==coin[j]||coinValue[i-coin[j]]!=0))//所需硬币个数减少了
- {
- minNum=coinNum[i-coin[j]]+1;//更新
- usedMoney=coin[j];//更新
- }
- }
- }
- coinNum[i]=minNum;
- coinValue[i]=usedMoney;
- }
- //输出结果
- if(coinValue[money]==0)
- cout<<"找不开零钱"<<endl;
- else
- {
- cout<<"需要最少硬币个数为:"<<coinNum[money]<<endl;
- cout<<"硬币分别为:";
- while(money>0)
- {
- cout<<coinValue[money]<<",";
- money-=coinValue[money];
- }
- }
- delete []coinNum;
- delete []coinValue;
- }
- int main()
- {
- int Money=18;
- int coin[]={1,2,5,9,10};
- FindMin(Money,coin,5);
- }