贪心算法学习笔记

贪心算法学习笔记

贪心算法的思想

顾名思义,贪心算法总是作出在当前看来最好的选择。也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择,不一定是全局最优的,即只有部分问题能够产生整体最优解。如单源最短路经问题,最小生成树问题等。在一些情况下,即使贪心算法不能得到整体最优解,其最终结果却是最优解的很近似。

贪心算法的基本要素

  • 贪心选择性质
    所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。
  • 具有最优子结构性质
    当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。问题的最优子结构性质是该问题可用动态规划算法或贪心算法求解的共同特征。

贪心算法的步骤和问题

贪心算法的解题步骤

①建立数学模型来描述问题。
②把求解的问题分成若干个子问题。
③对每个子问题求解,得到子问题的局部最优解。
④把子问题的解局部最优解合成原来解问题的一个解。
贪心策略的前提是:局部最优策略能导致产生全局最优解。
实际上,贪心算法使用的情况比较少,一般对一个问题分析是否适用于贪心算法,可以先选择该问题下>的几个实际数据进行分析可以做出判断。

找零钱的问题:

在贪心算法里面最常见的莫过于找零钱的问题了,题目大意如下,对于人民币的面值有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;
}

贪心算法与动态规划算法的对比

  • 相同点:
    要求原问题必须有最优子结构。
  • 不同点:
    贪心法的计算方式“自顶向下”,但并不等待子问题求解完毕后再选择使用哪一个,而是通过一种策略直接选择一个子问题去求解,没被选择的子问题直接抛弃。这种所谓“最优选择”的正确性需要用归纳法证明。而动态规划不管是采用自底向上还是自顶向下的计算方式,都是从边界开始向上得到目标问题的解(即考虑所有子问题)。贪心算法是通过做一系列的选择(贪心选择)来给出某一问题的最优解,在动态规划中,每一步都要做出选择,但是这些选择依赖于子问题的解。

以谈恋爱举例:
很多人来追求你。 贪心算法就是你根据你现在对他们的了解,你喜欢漂亮的,你挑一个最漂亮的,你喜欢有钱的,你挑一个最有钱的,只在意当前的最佳选择; 动态规划算法就是你对他们进行了一番深入的调查和了解之后,人品、物质、颜值等,最终选择和谁在一起!

贪心算法的证明方法

对许多最优化问题来说,采用动态规划方法来决定最佳选择有点“杀鸡用牛刀”了,只要采用另一些更简单有效的算法就行了。贪心算法是使所做的选择看起来都是当前最佳的,期望通过所做的局部最优选择来产生出一个全局最优解。贪心算法对大多数优化问题来说能产生最优解,但也不一定总是这样的。所有如果希望贪心算法得到全局最优,需要对贪心算法进行证明。
方法:

第一数学归纳法
第一数学归纳法可以概括为以下三步:
(1)归纳奠基:证明当n=1时命题成立;
(2)归纳假设:假设当n=k时命题成立;
(3)归纳递推:由归纳假设推出当n=k+1时命题也成立.
理解:如果假设(2)成立,即:命题P(n)成立,推出命题P(n+1)成立(n为任意正整数,表明该推导数量的无穷性)。根据此假设,可以得到P(n)→P(n+1)为真,亦即有:P(1)→P(2),P(2)→P(3),P(3)→P(4),…,P(n)→P(n+1)为真,则得P(n)成立。

第二数学归纳法
第一数学归纳法可以概括为以下三步:
命题P(n)满足:
(1)当n=1时,P(1)成立
(2)假设对于正整数k,当n<k,命题P(n)成立时,命题P(n=k)也成立
(3)那么,命题P(n)对于一切正整数都成立
理解:如果假设(2)成立,即:P(1),P(2),…,P(k-1)成立(k为任意正整数,表明成立命题数量的无穷性),可以推出P(k)成立。亦即:P(1),P(2),…,P(k-1)→P(k)的推导为真(P(1),P(2),…,P(k-1)为真),此时P(n)对一切正整数成立。一般情况下P(k)不复杂时,无需把P(1),P(2),…,P(k-1)成立 这些条件全用上,部分使用即可。例如只需P(k-2),P(k-1)即可推出P(k)。

以多米诺骨牌为例的话:
第一归纳法:第一个牌会倒,且有规则:前一张牌倒,后一张牌必定会倒。牌会一直倒下去(成立下去)
第二归纳法:前一批牌会倒,且有规则:前一批牌倒,前一批牌紧接着的下一张牌必定会倒。牌会一直倒下去(成立下去)
显然第二(强归纳法)归纳法与第一归纳法相比,是把一批牌看做成一张牌,初始条件由一张牌,变成了一批牌。可能这就是它强的原因吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值