贪心
基本思想
狭义的贪心算法指的是解最优化问题的一种特殊方法,解决过程中总是做出当下最好的选择,因为具有最优子结构的特点,局部最优解可以得到全局最优解;这种贪心算法是动态规划的一种特例。能用贪心解决的问题,也可以用动态规划解决。
而广义的贪心指的是一种通用的贪心策略,基于当前局面而进行贪心决策。
基本要素
贪心选择性质
所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。
贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。
对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。
最优子结构性质
当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。问题的最优子结构性质是该问题可用动态规划算法或贪心算法求解的关键特征。
基本思路
从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到算法中的某一步不能再继续前进时,算法停止。
存在的问题
-
不能保证求得的最后解是最佳的;
-
不能用来求最大或最小解问题;
-
只能求满足某些约束条件的可行解的范围。
贪心/分治/dp的区别
经典问题
找零钱问题
问题描述
对于人民币的面值有1元 5元 10元 20元 50元 100元,下面要求设计一个程序,输入找零的钱,输出找钱方案中最少张数的方案,比如123元,最少是1张100的,1张20的,3张1元的,一共5张!
解析:这样的题目运用的贪心策略是每次选择最大的钱,如果最后超过了,再选择次大的面值,然后次次大的面值,一直到最后与找的钱相等
#include <iostream>
#include <cmath>
using namespace std;
int main(int argc, char* argv[])
{
int MoneyClass[6] = {100,50,20,10,5,1}; //记录钱的面值
int MoneyIndex [6] ={0}; //记录每种面值的数量
int MoneyAll,MoneyCount = 0,count=0;
cout<<"please enter the all money you want to exchange:"<<endl;
cin>>MoneyAll;
for(int i=0;i<6;) //只有这个循环才是主体
{
if( MoneyCount+MoneyClass[i] > MoneyAll)
{
i++;
continue;
}
MoneyCount += MoneyClass[i];
++ MoneyIndex[i];
++ count;
if(MoneyCount == MoneyAll)
break;
}
for(i=0;i<6;++i) //控制输出的循环
{
if(MoneyIndex[i] !=0 )
{
switch(i)
{
case 0:
cout<<"the 100 have:"<<MoneyIndex[i]<<endl;
break;
case 1:
cout<<"the 50 have:"<<MoneyIndex[i]<<endl;
break;
case 2:
cout<<"the 20 have:"<<MoneyIndex[i]<<endl;
break;
case 3:
cout<<"the 10 have:"<<MoneyIndex[i]<<endl;
break;
case 4:
cout<<"the 5 have:"<<MoneyIndex[i]<<endl;
break;
case 5:
cout<<"the 1 have:"<<MoneyIndex[i]<<endl;
break;
}
}
}
cout<<"the total money have:"<<count<<endl;
system("pause");
return 0;
}