算法导论-贪心算法
贪心算法问题解决策略概述
贪心算法问题解决策略概述贪心算法(Greedy Algorithm)是一种简单而有效的问题解决策略,通过每一步的局部最优选择,最终达到全局最优解。
其基本思想是从问题的某个初始解出发,通过贪心的选择,逐步得到一个更优解,以求解整个问题。
本文将对贪心算法的基本原理以及应用领域进行概述。
一、贪心算法的基本原理贪心算法的核心思想是每一步都做出当前的最优选择,将问题分解为一系列子问题,并进行局部最优解的选择,最终得到全局最优解。
二、适用条件贪心算法适用于具有贪心选择性质的问题,即通过局部最优解可以得到全局最优解。
贪心选择性质是指每一步的选择只依赖于当前状态,不受其他步骤的影响。
三、典型应用1. 最小生成树问题:在一个连通图中,找出一个包含所有顶点的边的子集,使得这个子集形成一个树,且所有边的权值之和最小。
2. 哈夫曼编码问题:在编码问题中,通过给频率较高的字符分配较短的编码,从而使得编码的总长度最短。
3. 区间调度问题:给定一组区间,选择尽量多的互不重叠的区间。
4. 零钱支付问题:给定一定面额的硬币和一个要支付的金额,找出支付方式使得所需硬币的数量最少。
5. 背包问题的一些变体:如01背包问题、完全背包问题等。
四、算法步骤贪心算法的思路是通过局部最优解来构建全局最优解。
其一般步骤如下:1. 建立数学模型来描述问题。
2. 将问题分解为若干个子问题。
3. 对每个子问题求解,得到局部最优解。
4. 对所有子问题的局部最优解进行整合,得到原问题的最优解。
五、优缺点贪心算法的优点在于简单、高效,能够快速地找到一个近似最优解。
但是它也有一些缺点,即不能保证能够得到全局最优解,因为贪心策略是基于局部最优的选择,并不能考虑全局情况。
六、总结贪心算法作为一种简单而有效的问题解决策略,在许多实际问题中发挥着重要作用。
通过每一步的局部最优选择,贪心算法能够快速地找到一个近似最优解。
但需要注意的是,贪心算法并不能保证一定能够得到全局最优解,因此在具体应用中需要谨慎分析问题的特点,判断是否适合采用贪心算法。
信息学奥林匹克竞赛指导之基础算法—贪心算法
重量按比例计算。
7
-贪心算法
贪心算法的经典实例
• 思路点拨:本问题是在上一个问题的基础上增加了价值项,所以不能简
单地向上一题那样先选出轻的(轻的可能其价值也小),也不能先拿价
值大的(它可能特别重),而应该综合考虑两个因素。一种直观的贪心
可乘两个人。求用最少的船载所有人的方案。
8
-贪心算法
贪心算法的经典实例
• 思路点拨:考虑最轻的人i,他应该和谁一起乘呢?如果每个人都不能和
他一起乘,则只能每人乘一艘船。否则他应该选择能和他一起乘的人中
最重的一个人j。这样的选择只是让“眼前”的浪费最少,因此它是一种
贪心策略。
• 证明:
• 情况1:i不和任何一个人同乘一艘船,那么可以把j拉过来和他一起乘,总船数不会
法不从整体最优考虑,它所做出的选择只是局部最优解。
3
-贪心算法
贪心算法的概念及其特点
• 贪心算法是从问题的初始状态出发,通过若干次的贪心选择而得
到的最优值的一种求解问题的策略。
• 特点:
• 贪心选择:所谓贪心选择是指应用同一规则,将原问题变为一个相似的
但规模更小的子问题,而后的每一步都是当前看似最佳的选择,且这种
29
-贪心算法
贪心算法的经典应用-3
• 【输出格式】
• 对每组测试数据输出一个数字,表示要浇灌整块草坪所需喷头数
目的最小值。如果所有喷头都打开还不能浇灌整块草坪,则输出1。
• 【样例输入】
•3
• 8 20 2
•53
30
-贪心算法
贪心算法的经典应用-3
•
•
•
算法导论第4章
12
4.2 贪心算法的基本要素
2、最优子结构性质
当一个问题的最优解包含其子问题的最优解时, 称此问题具有最优子结构性质 称此问题具有最优子结构性质。问题的最优子结构性 最优子结构性质。问题的最优子结构性 质是该问题可用动态规划算法或贪心算法求解的关键 特征。
13
4.2 贪心算法的基本要素
3、贪心算法与动态规划算法的差异
2
顾名思义,贪心算法总是作出在当前看来最好的选择。 也就是说贪心算法并不从整体最优考虑,它所作出的选择 局部最优选择。当然,希望贪心算法 只是在某种意义上的局部最优 只是在某种意义上的局部最优选择。当然,希望贪心算法 得到的最终结果也是整体最优的。虽然贪心算法不能对所 有问题都得到整体最优解,但对许多问题它能产生整体最 优解。如单源最短路经问题,最小生成树问题等。在一些 情况下,即使贪心算法不能得到整体最优解,其最终结果 却是最优解的很好近似。
16
4.2 贪心算法的基本要素
用贪心算法解背包问题的基本步骤:
首先计算每种物品单位重量的价值Vi/Wi,然后,依贪心 首先计算每种物品单位重量的价值Vi/Wi,然后,依贪心 选择策略,将尽可能多的单位重量价值最高 选择策略,将尽可能多的单位重量价值最高的物品装入背包。 单位重量价值最高的物品装入背包。 若将这种物品全部装入背包后,背包内的物品总重量未超过 C,则选择单位重量价值次高的物品并尽可能多地装入背包。 依此策略一直地进行下去,直到背包装满为止。 具体算法可描述如下页:
贪心算法知识点总结
贪心算法知识点总结1. 基本原理贪心算法的基本原理是每一步都选择当前状态下的最优解,以期望最终得到全局最优解。
具体来说,贪心算法通常可以分为以下几个步骤:1)从问题的某个初始解出发2)采用一种迭代的方式,逐步将初始解进行优化3)每一步都是基于当前状态的最优选择来进行优化4)直到无法再进行优化,得到问题的最优解由于贪心算法每一步都要选择局部最优解,因此贪心算法通常具有高效性。
然而,贪心算法并不适用于所有问题,其结果不一定是全局最优解。
因此,在使用贪心算法时需要注意问题的特性和约束条件,以免得到错误的结果。
2. 适用情况贪心算法通常适用于满足以下条件的问题:1)问题的最优解满足“最优子结构”性质:即问题的最优解包含了其子问题的最优解2)问题的求解过程具有“贪心选择性”:即每一步都选择当前状态下的最优解,并不需要考虑未来的后果3)问题的约束条件可以通过局部最优选择满足全局最优解:即问题的解空间中存在一些局部最优解,可以通过一系列的局部最优解构建全局最优解在实际应用中,贪心算法通常用于求解最优化问题,如最小生成树、最短路径、任务调度等问题。
由于贪心算法的高效性,它通常能够在较短的时间内得到较为接近最优解的结果。
然而,贪心算法并不适用于所有问题,对于一些问题,贪心算法将得到错误的结果。
因此,在使用贪心算法时需要谨慎选择问题类型和约束条件,以避免错误的结果。
3. 贪心算法实例在下面的部分,我们将介绍一些常见的贪心算法实例,包括背包问题、活动安排问题、霍夫曼编码等。
3.1 背包问题背包问题是一个经典的优化问题,它包括0-1背包问题、分数背包问题等多种类型。
在0-1背包问题中,给定n种物品和一个容量为C的背包,每种物品i的重量为w[i],价值为v[i],求在不超过背包容量的情况下,如何选择物品放入背包,可以使得背包中的总价值最大。
对于0-1背包问题,贪心算法通常不能得到最优解。
然而,在分数背包问题中,贪心算法通常可以得到近似的最优解。
算法设计与分析 第五章 贪心算法
第五章 贪心算法§1.贪心算法基本思想找零钱 假如售货员需要找给小孩67美分的零钱。
现在,售货员手中只有25美分、10美分、5美分和1美分的硬币。
在小孩的催促下,售货员想尽快将钱找给小孩。
她的做法是:先找不大于67美分的最大硬币25美分硬币,再找不大于67-25=42美分的最大硬币25美分硬币,再找不大于42-25=17美分的最大硬币10美分硬币,再找不大于17-10=7美分的最大硬币5美分硬币,最后售货员再找出两个1美分的硬币。
至此,售货员共找给小孩6枚硬币。
售货员的原则是拿尽可能少的硬币个数找给小孩。
从另一个角度看,如果售货员将捡出的硬币逐一放在手中,最后一起交给小孩,那么售货员想使自己手中的钱数增加的尽量快些,所以每一次都尽可能地捡面额大的硬币。
装载问题 有一艘大船用来装载货物。
假设有n 个货箱,它们的体积相同,重量分别是n w w w ,,21 ,货船的最大载重量是c 。
目标是在船上装最多货箱该怎样装?如果用1=i x 表示装第i 个货箱,而0=i x 表示不装第i 个货箱,则上述问题是解优化问题:求n x x x ,,,21 ,∑=ni i x 1max (5.1.1)c x i ni i ≤∑=1w (5.1.2)贪心方法,顾名思义,是在决策中总是作出在当前看来是最好的选择。
例如找零钱问题中,售货员每捡一个硬币都想着使自己手中的钱尽快达到需要找钱的总数。
在装载问题中,每装一个货箱都想着在不超重的前提下让船装更多的箱子。
但是贪心方法并未考虑整体最优解,它所作出的选择只是在某种意义上的局部最优选择。
当然,在采用贪心算法时未必不希望结果是整体最优的。
事实上,有相当一部分问题,采用贪心算法能够达到整体最优,如前面的找零钱问题以及后面将要讲到的单点源最短路径问题、最小生成树问题、工件排序问题等。
为了更好理解贪心算法,我们将装载问题稍加推广,考虑可分割的背包问题。
背包问题 已知容量为M 的背包和n 件物品。
第三章 贪心算法
2021/2/22
5
如果问题改成:砝码的种类分别为11克、5克和1克, 待称的物体是15克。用贪婪算法应先选一个11克的,然 后选四个1克的,共用五个砝码。这不是最优结果,只 要用三个5克的砝码就够了。
贪婪算法虽不能保证得到最优结果,但对于一些除
了“穷举”方法外没有有效算法的问题,用贪婪算法往
往能很快地得出较好的结果,如果此较好结果与最优结 果相差不是很多的话,此方法还是很实用的。
2021/2/22
9
当n不太大时,适当的取k值,此改进方法常常可以得到 最优解,但不能因此就说一般背包问题有多项式算法。 当n增大时,k不能随着n不断的加大,如k随n增大而同 时加大,其复杂性就是指数型而不是多项式型的了,而 如k取值较小,又不能保证得出最优解。
0021算法笔记——【贪心算法】贪心算法与精彩活动安排问题
0021算法笔记——【贪心算法】贪心算法与活动安排问题1、贪心算法(1)原理:在对问题求解时,总是做出在当前看来是最好的选择。
也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题他能产生整体最优解或者是整体最优解的近似解。
(2)特性:贪心算法采用自顶向下,以迭代的方法做出相继的贪心选择,每做一次贪心选择就将所求问题简化为一个规模更小的子问题,通过每一步贪心选择,可得到问题的一个最优解,虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪婪法不要回溯。
能够用贪心算法求解的问题一般具有两个重要特性:贪心选择性质和最优子结构性质。
1)贪心选择性质所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。
这是贪心算法可行的第一个基本要素。
贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。
对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。
证明的大致过程为:首先考察问题的一个整体最优解,并证明可修改这个最优解,使其以贪心选择开始。
做了贪心选择后,原问题简化为规模更小的类似子问题。
然后用数学归纳法证明通过每一步做贪心选择,最终可得到问题的整体最优解。
其中,证明贪心选择后的问题简化为规模更小的类似子问题的关键在于利用该问题的最优子结构性质。
2)最优子结构性质当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。
(3)贪心算法与动态规划算法的差异:动态规划和贪心算法都是一种递推算法,均有最优子结构性质,通过局部最优解来推导全局最优解。
两者之间的区别在于:贪心算法中作出的每步贪心决策都无法改变,因为贪心策略是由上一步的最优解推导下一步的最优解,而上一部之前的最优解则不作保留,贪心算法每一步的最优解一定包含上一步的最优解。
贪 心 算 法
贪心算法及几个常用的例题贪心算法:一、基本概念:所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。
也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。
贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。
必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关。
所以对所采用的贪心策略一定要仔细分析其是否满足无后效性。
二、贪心算法的基本思路:1.建立数学模型来描述问题。
2.把求解的问题分成若干个子问题。
3.对每一子问题求解,得到子问题的局部最优解。
4.把子问题的解局部最优解合成原来解问题的一个解。
三、贪心算法适用的问题贪心策略适用的前提是:局部最优策略能导致产生全局最优解。
实际上,贪心算法适用的情况很少。
一般,对一个问题分析是否适用于贪心算法,可以先选择该问题下的几个实际数据进行分析,就可做出判断。
四、贪心算法的实现框架从问题的某一初始解出发;while (能朝给定总目标前进一步)利用可行的决策,求出可行解的一个解元素;由所有解元素组合成问题的一个可行解;五、贪心策略的选择因为用贪心算法只能通过解局部最优解的策略来达到全局最优解,因此,一定要注意判断问题是否适合采用贪心算法策略,找到的解是否一定是问题的最优解。
几个经典的例子:一、定义什么是贪心算法呢?所谓贪心算法是指,在对问题求解时,总是做出在当前看来最好的选择。
也就是说,不从整体最优解出发来考虑,它所做出的仅是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题都能产生整体最优解或整体最优解的近似解。
贪心算法的基本思路如下:1. .建立数学模型来描述问题。
2. 把求解的问题分成若干个子问题。
3. 对每个子问题求解,得到每个子问题的局部最优解。
4. 把每个子问题的局部最优解合成为原来问题的一个解。
算法导论-贪心算法
贪心算法可以看作是动态规划的一种特例,其中只保 留了与当前状态和当前选择相关的子问题的解,而不
是保留所有子问题的解。
贪心算法通常在每一步选择中只考虑当前状态下的局 部最优解,而不是考虑所有可能的选择和未来的状态。
贪心算法的经述 • 贪心算法的基本思想 • 贪心算法的经典问题 • 贪心算法的实现与优化 • 贪心算法的性能分析 • 总结与展望
贪心算法概述
01
定义与特点
定义
贪心算法是一种在每一步选择中都采取当前情况下最好或最优(即最有利)的 选择,从而希望导致结果是最好或最优的算法。
无法保证全局最优解
贪心算法可能只得到局部最优解,而非全局最 优解。
缺乏理论支持
贪心算法的理论基础尚不完备,难以对所有情况做出准确预测。
贪心算法与其他算法的比较
与动态规划算法比较
动态规划算法通过将问题分解为子问题来求解,适合处理具有重叠子问题和最优子结构的问题;而贪 心算法则是每一步都选择当前最优的选择,希望这样的局部最优选择能够导致全局最优解。
法的时间复杂度。
需要注意的是,贪心算法并不总是能够提供最优解,因此在实际应用中, 需要权衡时间复杂度和解的质量。
空间复杂度分析
贪心算法的空间复杂度主要取决于算法 的存储需求。在某些情况下,贪心算法 可能需要大量的存储空间来存储中间结
果或数据结构。
在分析贪心算法的空间复杂度时,需要 考虑算法所需的存储空间和存储结构的 复杂性。通过将每个存储需求的空间复 杂度相加,可以得出整个算法的空间复
与分治算法比较
分治算法是将问题分解为若干个子问题,然后递归地求解这些子问题,再将子问题的解合并起来得到 原问题的解;而贪心算法是在每一步都做出在当前状态下最好或最优(即最有利)的选择,希望这样 的局部最优选择能够导致全局最优解。
贪心算法的图文讲解
总结
• 在对问题求解时,会选择当前看起来最有希望成功的边(任务) 。一旦做出决定,它就不会再重新考虑,也不会关心后面会引发 什么情况。也就是说,不从整体最优上加以考虑,它所做出的是 在某种意义上的局部最优解。 • 贪心算法是一种能够得到某种度量意义下的最优解的分级处理方 法,通过一系列的选择来得到一个问题的解,而它所做的每一次 选择都是当前状态下某种意义的最好选择,即贪心选择。即希望 通过问题的局部最优解来求出整个问题的最优解。这种策略是一 种很简洁的方法,对许多问题它能产生整体最优解,但不能保证 总是有效,因为它不是对所有问题都能得到整体最优解,只能说 其解必然是最优解的很好近似值
对于这个问题我们有以下几种情况:设加油次数为k,每个加油 站间距离为a[i];i=0,1,2,3……n (1)始点到终点的距离小于N,则加油次数k=0; (2)始点到终点的距离大于N时: A 加油站间的距离相等,即a[i]=a[j]=L=N,则加油次数最少k=n ; B 加油站间的距离相等,即a[i]=a[j]=L>N,则不可能到达终点; C 加油站间的距离相等,即a[i]=a[j]=L<N,则加油次数 k=n/N(n%N==0)或k=[n/N]+1(n%N!=0); D 加油站间的距离不相等,即a[i]!=a[j],则加油次数k通过贪心 算法求解。
•
• • 贪心的基本思想
• 用局部解构造全局解,即从问题的某一个初始解逐步逼 近给定的目标,以尽可能快地求得更好的解。当某个算 法中的某一步不能再继续前进时,算法停止。贪心算法 思想的本质就是分处理 出一个最好的方案。 • 利用贪心策略解题,需要解决两个问题: • (1)该题是否适合于用贪心策略求解; • (2)如何选择贪心标准,以得到问题的最优/较优解。
03贪心算法
第3章贪心算法贪心算法一般来说是解决“最优问题”,具有编程简单、运行效率高、空间复杂度低等特点。
是程序竞赛中的一个有力武器,受到广大同学们的青睐。
贪心算法一般是求“最优解”这类问题的。
最优解问题可描述为:有n个输入,它的解是由这n个输入的某个子集组成,并且这个子集必须满足事先给定的条件。
这个条件称为约束条件。
而把满足约束条件的子集称为该问题的可行解。
这些可行解可能有多个。
为了衡量可行解的优劣,事先给了一个关于可行解的函数,称为目标函数。
目标函数最大(或最小)的可行解,称为最优解。
贪心算法的正确性证明虽然不容易,但一些常见的方法还是值得总结的。
1.构造法根据描述的算法,用贪心的策略,依次构造出一个解,可证明一定是合法的解。
即用贪心法找可行解。
2.反证法用贪心的策略,依次构造出一个解S1。
假设最优解S2不同与S1,可以证明是矛盾的。
从而S1就是最优解。
3.调整法用贪心的策略,依次构造出一个解S1。
假设最优解S2不同与S1,找出不同之处,在不破坏最优性的前提下,逐步调整S2,最终使其变为S1。
从而S1也是最优解。
3.1 构造法构造法就是从一个空的解开始,根据贪心策略,逐步将新的内容加入原有的解中,直到满足要求或无法将新的元素加入为止。
也可以将使用相反的手段,即先将整个解设定为一个最大的集合,然后,用贪心策略逐步从原有解中取出元素,直至满足要求或无法取出元素为止。
本节例题将介绍第一种贪心的例子。
3.1.1 〖案例1〗订票一家票务办公室为音乐会售票。
它们以出售某一固定数量的连号票(简称套票)来替代常见的单张票销售。
票务办收到了大量的购票订单。
套票的订单以该套票中最小的座位号作为标识。
然而票务办并不能满足所有的订单,而且如果他们完全按照观众的要求来分·60· ACM 程序设计培训教程配座位,就会出现很多空位。
为此票务办采取了如下的座位分配和价格策略:如果一个订单被接受且完全按照观众的要求安排座位,那么观众就要付全价(每套票2 petaks);如果一个订单虽被接受但是至少有一个座位与观众的要求不同,那么顾客只需付半价(每套票1 petaks)。
贪心算法的理解-概述说明以及解释
贪心算法的理解-概述说明以及解释1.引言1.1 概述概述部分的内容可以描述贪心算法的基本概念和作用。
贪心算法是一种常用的求解优化问题的算法思想,其核心思想是在每一步都选择当前最优解,从而希望最终达到全局最优解。
贪心算法通常适用于那些具有最优子结构特性和贪心选择性质的问题。
具体来说,贪心算法通常分为以下几个步骤:首先,根据问题的特性确定问题的目标函数或者判断问题的可行解的标准;其次,把原问题分解为若干个子问题,每次选择最优解作为当前问题的解;接着,对所选取的解进行判断,如果满足问题的约束条件,则放入解集中,否则舍弃;最后,递归或者迭代地处理下一个子问题,直到找出全局最优解。
贪心算法的应用非常广泛,它可以用来解决许多实际问题,比如最小生成树、最短路径、背包问题等。
贪心算法的优点在于简单、高效,其时间复杂度通常较低。
然而,贪心算法也有其局限性,它只关注当前的最优解而不考虑全局的最优解,因此在某些问题上可能会得到次优解甚至是错误的解。
综上所述,贪心算法是一种重要的优化算法思想,通过不断选择当前最优解来求解问题。
它的应用广泛,具有高效简单的特点,但也存在局限性。
在今后的发展中,我们可以对贪心算法进行改进,使其在更多的问题中发挥更强大的作用。
1.2 文章结构文章结构部分:本文分为引言、正文和结论三个部分。
引言部分主要概述了本文的主题——贪心算法,并介绍了文章的结构和目的。
正文部分将重点讲解贪心算法的定义、原理、应用场景以及优缺点。
首先,在2.1节中,我们将介绍什么是贪心算法。
贪心算法是一种在每一步选择中都选择当前情况下最好或最优的选择,以期望能够导致全局最优解的算法。
其次,在2.2节中,我们将详细解析贪心算法的原理。
贪心算法的核心思想是通过不断地做出局部最优选择,从而最终得到全局最优解。
我们将使用一些具体的示例来说明贪心算法的运作方式。
然后,在2.3节中,我们将探讨贪心算法的应用场景。
贪心算法在很多实际问题中都有广泛的应用,如任务调度、背包问题、最短路径等。
算法总结---最常用的五大算法(算法题思路)
算法总结---最常⽤的五⼤算法(算法题思路)算法总结---最常⽤的五⼤算法(算法题思路)⼀、总结⼀句话总结:> 【明确所求:dijkstra是求点到点的距离,辅助数组就是源点到⽬标点的数组】> 【最简实例分析:⽐如思考dijkstra:假设先只有三个点】1、贪⼼算法是什么?> 当前看来最好的选择> 局部最优解> 可能得到整体最优解或是最优解的近似解贪⼼算法(⼜称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。
也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。
贪⼼算法不是对所有问题都能得到整体最优解,但对范围相当⼴泛的许多问题他能产⽣整体最优解或者是整体最优解的近似解。
2、贪⼼算法实例?> 求最⼩⽣成树的Prim算法:【边集中依次选取那些权值最⼩的边】> 求最⼩⽣成树的Kruskal算法:【和求最短路径有点相似:不过这⾥是求两个集合之间的距离】:【⼀维中间数组记录到当前已经选择顶点的最短距离】:【⼆维表记录每个点到每个点的最短距离】> 计算强连通⼦图的Dijkstra算法:【和最⼩⽣成树Kruskal类似】【⼆维表记录每个点到每个点的最短距离】【明确所求:dijkstra是求点到点的距离,辅助数组就是源点到⽬标点的数组】【每次从辅助数组中选择最⼩的,⽤选出的点来更新辅助数组】【最简实例分析:⽐如思考dijkstra:假设先只有三个点】> 构造huffman树的算法:【每次都选取权值⼩的两个点合成⼆叉树】Kruskal算法简述在带权连通图中,不断地在边集合中找到最⼩的边,如果该边满⾜得到最⼩⽣成树的条件,就将其构造,直到最后得到⼀颗最⼩⽣成树。
假设 WN=(V,{E}) 是⼀个含有 n 个顶点的连通⽹,则按照克鲁斯卡尔算法构造的过程为:先构造⼀个只含 n 个顶点,⽽边集为空的⼦图,若将该⼦图中各个顶点看成是各棵树上的根结点,则它是⼀个含有 n 棵树的⼀个森林。
《算法导论》读书笔记之第16章贪心算法—活动选择问题
《算法导论》读书笔记之第16章贪心算法—活动选择问题前言:贪心算法也是用来解决最优化问题,将一个问题分成子问题,在现在子问题最优解的时,选择当前看起来是最优的解,期望通过所做的局部最优选择来产生一个全局最优解。
书中先从活动选择问题来引入贪心算法,分别采用动态规划方法和贪心算法进行分析。
本篇笔记给出活动选择问题的详细分析过程,并给出详细的实现代码进行测试验证。
关于贪心算法的详细分析过程,下次在讨论。
1、活动选择问题描述有一个需要使用每个资源的n个活动组成的集合S= {a1,a2,···,a n },资源每次只能由一个活动使用。
每个活动a i都有一个开始时间s i 和结束时间f i,且0≤s i<f i<∞。
一旦被选择后,活动a i就占据半开时间区间[s i,f i)。
如果[s i,f i]和[s j,f j]互不重叠,则称a i和a j两个活动是兼容的。
该问题就是要找出一个由互相兼容的活动组成的最大子集。
例如下图所示的活动集合S,其中各项活动按照结束时间单调递增排序。
从图中可以看出S中共有11个活动,最大的相互兼容的活动子集为:{a1,a4,a8,a11,}和{a2,a4,a9,a11}。
2、动态规划解决过程(1)活动选择问题的最优子结构定义子问题解空间S ij是S的子集,其中的每个获得都是互相兼容的。
即每个活动都是在a i结束之后开始,且在a j开始之前结束。
为了方便讨论和后面的计算,添加两个虚构活动a0和a n+1,其中f0=0,s n+1=∞。
结论:当i≥j时,S ij为空集。
如果活动按照结束时间单调递增排序,子问题空间被用来从S ij中选择最大兼容活动子集,其中0≤i<j≤n+1,所以其他的S ij都是空集。
最优子结构为:假设S ij的最优解A ij包含活动a k,则对S ik的解A ik和S kj的解A kj必定是最优的。
通过一个活动a k将问题分成两个子问题,下面的公式可以计算出S ij的解A ij。
算法导论-贪心算法
算法导论——贪心算法求解最优化问题的算法通常需要经过一系列的步骤,在每个步骤都面临多种选择。
对于许多最优化问题,使用动态规划算法来求最优解有些杀鸡用牛刀了,可以使用更简单、更高效的算法。
贪心算法(greedy algorithm)就是这样的算法,它在每一步都做出当时看起来最佳的选择。
也就是说,它总是做出局部最优的选择,寄希望这样的选择能导致全局最优解。
本章介绍一些贪心算法能找到最优解的最优化问题。
贪心算法并不保证得到最优解,但对很多问题确实可以求得最优解。
我们首先在16.1节介绍一个简单但非平凡的问题—活动选择问题,这是一个可以用贪心算法求得最优解的问题。
首先考虑用动态规划方法解决这个问题,然后证明一直做出贪心选择就可以得到最优解,从而得到一个贪心算法。
16. 2节会回顾贪心方法的基本要素,并给出一个直接的方法,可用来证明贪心算法的正确性。
16. 3节提出贪心技术的一个重要应用:设计数据压缩编码(Huffman编码)。
在16. 4节中,我们讨论一种称为“拟阵"(matroid)的组合结构的理论基础,贪心算法总是能获得这种结构的最优解。
最后,16. 5节将拟阵应用于单位时间任务调度问题,每个任务均有截止时间和超时惩罚。
贪心方法是一种强有力的算法设计方法,可以很好地解决很多问题。
在后面的章节中,我们会提出很多利用贪心策略设计的算法,包括最小生成树(minimum-spanning-tree)算法(第23章)、单源最短路径的djikstra算法(第24章),以及集合覆盖问题的Chvatal贪心启发式算法(第35章)。
最小生成树算法提供了一个经典的贪心方法的例子。
16.1 贪心选择假如我们无需求解所有子问题就可以选择出一个活动加人到最优解,将会怎样?这将使我们省去递归式(16. 2)中固有的考查所有选择的过程。
实际上,对于活动选择问题,我们只需考虑一个选择:贪心选择。
对于活动选择问题,什么是贪心选择?直观上,我们应该选择这样一个活动,选出它后剩下的资源应能被尽量多的其他任务所用。
算法-04贪心算法
算法-04贪⼼算法1. Greedy贪⼼算法(greedy algorithm)。
贪⼼算法有很多经典的应⽤,⽐如霍夫曼编码(Huffman Coding)、Prim 和 Kruskal 最⼩⽣成树算法、还有 Dijkstra 单源最短路径算法。
最⼩⽣成树算法和最短路径算法,霍夫曼编码,看看它是如何利⽤贪⼼算法来实现对数据压缩编码,有效节省数据存储空间的。
贪⼼算法是⼀种在每⼀步选择中都采取在当前状态下最好或最优(即最有利)的选择,从⽽希望导致结果是全局最好或最优的算法。
2. 贪⼼算法与回溯和动态规划贪⼼算法与动态规划的不同点:贪⼼算法与动态规划的不同在于它对每个⼦问题的解决⽅案都做出选择,不能回退。
动态规划则会保存以前的运算结果,并根据以前的结果对当前进⾏选择,有回退功能。
贪⼼:当下做局部最优判断,同时是不能回退的;回溯:能够回退;动态规划:最优判断 + 回退;(带有最优判断的回溯就是动态规划)3. 适⽤情景简单地说,问题能够分解成⼦问题来解决,⼦问题的最优解能递推到最终问题的最优解。
这种⼦问题最优解称为最优⼦结构。
贪⼼算法与动态规划的不同在于它对每个⼦问题的解决⽅案都做出选择,不能回退。
动态规划则会保存以前的运算结果,并根据以前的结果对当前进⾏选择,有回退功能。
贪⼼法可以解决⼀些最优化问题,选最优选最近选最好都可以⽤贪⼼算法,如:求图中的最⼩⽣成树、求哈夫曼编码等。
然⽽对于⼯程和⽣活中的问题,贪⼼法⼀般不能得到我们所要求的答案(选择眼前最优,⼀般来说达不到全局最优)。
⼀旦⼀个问题可以通过贪⼼法来解决,那么贪⼼法⼀般是解决这个问题的最好办法。
由于贪⼼法的⾼效性以及其所求得的答案⽐较接近最优结果,贪⼼法也可以⽤作辅助算法或者直接解决⼀些要求结果不特别精确的问题。
4. 案例4.1 Coin Change钱币找零案例当硬币可选集合固定:Coins = [20, 10, 5, 1] 求最少可以⼏个硬币拼出总数。
常用算法与程序设计第五章贪心算法
➢ 对给定的n位高精度正整数,去掉其中k(k<n)个数 字后,按原左右次序将组成一个新的正整数,使 得剩下的数字组成的新数最大。
➢ 操作对象是一个可以超过有效数字位数的n位高 精度数,存储在数组a中。
➢ 每次删除一个数字,选择一个使剩下的数最大的数 字作为删除对象。之所以选择这样“贪心”的操 作,是因为删k个数字的全局最优解包含了删一个 数字的子问题的最优解。
作业: 一个数列由n个正整数组成,对该数列进行
一次操作:去除其中两项a、b,添加一项 a*b+1。经过n-1次操作后该数列剩一个数a, 试求a的最大值。
18
Visual FoxPro
5.5 覆盖问题
二分图是一个无向图,它的n 个顶点可二分为集 合A和集合B,且同一集合中的任意两个顶点在图中 无边相连(即任何一条边都是一个顶点在集合A中, 另一个在集合B中)。当且仅当B中的每个顶点至少 与A中一个顶点相连时,A的一个子集A‘ 覆盖集合B (或简单地说,A’ 是一个覆盖)。覆盖A‘ 的大小即 为A’ 中的顶点数目。当且仅当A‘ 是覆盖B的子集中最 小的时,A’ 为最小覆盖。
15
Visual FoxPro
物品可拆背包问题C程序设计代码如下:
➢ for(i=1;i<=n-1;i++) 大到小排序 */
/* 对n件物品按单位重量的效益从
➢ for(j=i+1;j<=n;j++)
➢ if(p[i]/w[i]<p[j]/w[j])
➢ { h=p[i];p[i]=p[j]; p[j]=h;
5.1 贪心算法概述
5.1.1 贪心算法
有一艘大船准备用来装载货物。所有待装货物都装在 货箱中且所有货箱的大小都一样,但货箱的重量都各不相 同。设第i个货箱的重量为wi(1≤i≤n),而货船的最大载 重量为c,我们的目的是在货船上装入最多箱的货物。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
算法导论——贪心算法求解最优化问题的算法通常需要经过一系列的步骤,在每个步骤都面临多种选择。
对于许多最优化问题,使用动态规划算法来求最优解有些杀鸡用牛刀了,可以使用更简单、更高效的算法。
贪心算法(greedy algorithm)就是这样的算法,它在每一步都做出当时看起来最佳的选择。
也就是说,它总是做出局部最优的选择,寄希望这样的选择能导致全局最优解。
本章介绍一些贪心算法能找到最优解的最优化问题。
贪心算法并不保证得到最优解,但对很多问题确实可以求得最优解。
我们首先在16.1节介绍一个简单但非平凡的问题—活动选择问题,这是一个可以用贪心算法求得最优解的问题。
首先考虑用动态规划方法解决这个问题,然后证明一直做出贪心选择就可以得到最优解,从而得到一个贪心算法。
16. 2节会回顾贪心方法的基本要素,并给出一个直接的方法,可用来证明贪心算法的正确性。
16. 3节提出贪心技术的一个重要应用:设计数据压缩编码(Huffman编码)。
在16. 4节中,我们讨论一种称为“拟阵"(matroid)的组合结构的理论基础,贪心算法总是能获得这种结构的最优解。
最后,16. 5节将拟阵应用于单位时间任务调度问题,每个任务均有截止时间和超时惩罚。
贪心方法是一种强有力的算法设计方法,可以很好地解决很多问题。
在后面的章节中,我们会提出很多利用贪心策略设计的算法,包括最小生成树(minimum-spanning-tree)算法(第23章)、单源最短路径的djikstra算法(第24章),以及集合覆盖问题的Chvatal贪心启发式算法(第35章)。
最小生成树算法提供了一个经典的贪心方法的例子。
16.1 贪心选择假如我们无需求解所有子问题就可以选择出一个活动加人到最优解,将会怎样?这将使我们省去递归式(16. 2)中固有的考查所有选择的过程。
实际上,对于活动选择问题,我们只需考虑一个选择:贪心选择。
对于活动选择问题,什么是贪心选择?直观上,我们应该选择这样一个活动,选出它后剩下的资源应能被尽量多的其他任务所用。
现在考虑可选的活动,其中必然有一个最先结束。
因此,直觉告诉我们,应该选择S中最早结束的活动,因为它剩下的资源可供它之后尽量多的活动使用。
(如果S中最早结束的活动有多个,我们可以选择其中任意一个)。
换句话说,由于活动已按结束时间单调递增的顺序排序,贪心选择就是活动a,。
选择最早结束的活动并不是本问题唯一的贪心选择方法,练习16.1-3要求设计其他贪心选择方法。
当做出贪心选择后,只剩下一个子问题需要我们求解:寻找在a,结束后开始的活动。
为什么不需要考虑在a1开始前结束的活动呢?因为s1<f1且f1是最早结束的活动,所以不会有活动的结束时间早s1。
因此,所有与a,兼容的活动都必须在al结束之后开始。
而且,我们已经证明活动选择问题具有最优子结构性质。
令为在ak结束后开始的任务集合。
当我们做出贪心选择,选择了a1后,剩下的S1是唯一需要求解的子问题。
最优子结构性质告诉我们,如果a1在最优解中,那么原问题的最优解由活动a1及子问题S1中所有活动组成。
现在还剩下一个大问题:我们的直觉是正确的吗?贪心选择——最早结束的活动——总是最优解的一部分吗?下面的定理证明了这一点。
定理16. 1考虑任意非空子问题Sk,令am是Sk中结束时间最早的活动则a。
在S*的某个最大兼容活动子集中。
证明 令Ak是Sk的一个最大兼容活动子集,且aj是Ak中结束时间最早的活动。
若aj=am,则已经证明am在Sk的某个最大兼容活动子集中。
若aj不等于am,令集合,即将Ak中的aj替换为am.Ak’中的活动都是不相交的,因为Ak中的活动都是不相交的,aj是Ak中结束时间最早的活动,而fm小于等于fj。
由于,因此得出结论Ak’也是Sk的一个最大兼容活动子集,且它包含am.因此,我们看到虽然可以用动态规划方法求解活动选择问题,但并不需要这样做(此外,我们并未检查活动选择问题是否具有重叠子问题性质)。
相反,我们可以反复选择最早结束的活动,保留与此活动兼容的活动,重复这一过程,直至不再有剩余活动。
而且,因为我们总是选择最早结束的活动,所以选择的活动的结束时间必然是严格递增的。
我们只需按结束时间的单调递增顺序处理所有活动,每个活动只考查一次。
求解活动选择问题的算法不必像基于表格的动态规划算法那样自底向上进行计算。
相反,可以自顶向下进行计算,选择一个活动放人最优解,然后,对剩余的子问题(包含与已选择的活动兼容的活动)进行求解。
贪心算法通常都是这种自顶向下的设计:做出一个选择,然后求解剩下的那个子问题,而不是自底向上地求解出很多子问题,然后再做出选择。
递归贪心算法我们已经看到如何绕过动态规划方法而使用自顶向下的贪心算法来求解活动选择问题,现在我们可以设计一个直接的递归过程来实现贪心算法。
过程RECURSIVE-ACTIVITY-SELECTOR的输人为两个数组s和f,表示活动的开始和结束时间,下标k指出要求解的子问题Sk,以及问题规模n。
它返回凡的一个最大兼容活动集。
我们假定输人的n个活动已经按结束时间的单调递增顺序排列好(公式(16. 1))。
如果未排好序,我们可以在O(n Ign)时间内对它们进行排序,结束时间相同的活动可以任意排列。
为了方便算法初始化,我们添加一个虚拟活动a0,其结束时间f0=0,这样子问题So就是完整的活动集S。
求解原问题即可调用RECURSIVE-ACTIVITY SELECTOR(s, f, 0, n)。
图16-1.显示了算法的执行过程。
在一次递归调用RECURSIVE-ACTIVITY-SELECTOR ( s,f, k, n)的过程中,第2^}3行while循环查找Sk中最早结束的活动。
循环检查ak+1,ak+2,...,an,直至找到第一个与ak兼容的活动am,此活动满足sm>=fk。
如果循环因为查找成功而结束,第5行返回{am}与RECURSIVE-ACTIVITY SELECTOR<s,fm,n)返回的Sm的最大子集的并集。
循环也可能因为m>n而终止,这意味着我们已经检查了Sk中所有活动,未找到与a*兼容者。
在此情况下,,因此第6行返回.假定活动已经按结束时间排好序,则递归调用RECURSIVE-ACTIVITY-SELECTOR(s, f,0, n)的运行时间为O(n),我们稍后证明这个结论。
在整个递归调用过程中,每个活动被且只被第2行的while循环检查一次。
特别地,活动ai在k<i的最后一次调用中被检查。
迭代贪心算法我们可以很容易地将算法转换为迭代形式。
过程RECURSIVE-ACTIVITY SELECTOR几乎就是“尾递归”:它以一个对自身的递归调用再接一次并集操作结尾。
将一个尾递归过程改为迭代形式通常是很直接的,实际上,某些特定语言的编译器可以自动完成这一工作。
如前所述,RECURSIVEACTIVITY-SELECTOR用来求解子问题凡,即由最后完成的任务组成的子问题。
过程GREEDY-ACTIVITY-SELECTOR是过程RECURSIVE ACTIVITY-SELECTOR 的一个迭代版本。
它也假定输人活动已按结束时间单调递增顺序排好序。
它将选出的活动存人集合A中,并将A返回调用者。
过程执行如下。
变量k记录了最近加人集合A的活动的下标,它对应递归算法中的活动ak。
由于我们按结束时间的单调递增顺序处理活动,人总是A中活动的最大结束时间。
也就是说,(16.3)第2~3行选择活动a1,将A的初值设置为只包含此活动,并将k的初值设为此活动的下标。
第4~7行的for循环查找凡中最早结束的活动。
循环依次处理每个活动am,am若与之前选出的活动兼容,则将其加人A,这样选出的am必然是S。
中最早结束的活动。
为了检查活动am是否与A中所有活动都兼容,过程检查公式(16.3)是否成立,即检查活动的开始时间sm 是否不早于最近加人到A中的活动的结束时间fk。
如果活动am是兼容的,第6~7行将其加人A中,并将k设置为m.GREEDY-ACTIVITY-SELECTOR(s,f)返回的集合A与RECURSIVE ACTIVITYSELECTOR(s,f,0,n)返回的集合完全相同。
与递归版本类似,在输人活动已按结束时间排序的前提下,GREEDY-ACTIVITY-SELECTOR的运行时间为O(n).16. 2贪心算法原理贪心算法通过做出一系列选择来求出问题的最优解。
在每个决策点,它做出在当时看来最佳的选择。
这种启发式策略并不保证总能找到最优解,但对有些问题确实有效,如活动选择问题。
本节讨论贪心方法的一些一般性质。
16. l节中设计贪心算法的过程比通常的过程繁琐一些,我们当时经过了如下几个步骤:1.确定问题的最优子结构。
2.设计一个递归算法(对活动选择问题,我们给出了递归式(16.2),但跳过了基于此递归式设计递归算法的步骤)。
3.证明如果我们做出一个贪心选择,则只剩下一个子问题。
4.证明贪心选择总是安全的(步骤3, 4的顺序可以调换)。
5.设计一个递归算法实现贪心策略。
6.将递归算法转换为迭代算法。
在这个过程中,我们详细地看到了贪心算法是如何以动态规划方法为基础的。
例如,在活动选择问题中,我们首先定义了子问题Sij,其中2和7都是可变的。
然后我们发现,如果总是做出贪心选择,则可以将子问题限定为Sk的形式。
与这种繁琐的过程相反,我们可以通过贪心选择来改进最优子结构,使得选择后只留下一个子问题。
在活动选择问题中,我们可以一开始就将第二个下标去掉,将子问题定义为Sk的形式。
然后,我们可以证明,贪心选择(Sk中最早结束的活动am)与剩余兼容活动集的最优解组合在一起,就会得到Sk的最优解。
更一般地,我们可以按如下步骤设计贪心算法:1.将最优化问题转化为这样的形式:对其做出一次选择后,只剩下一个子问题需要求解。
2.证明做出贪心选择后,原问题总是存在最优解,即贪心选择总是安全的。
3.证明做出贪心选择后,剩余的子问题满足性质:其最优解与贪心选择组合即可得到原问题的最优解,这样就得到了最优子结构。
在本章剩余部分中,我们将使用这种更直接的设计方法。
但我们应该知道,在每个贪心算法之下,几乎总有一个更繁琐的动态规划算法。
我们如何证明一个贪心算法是否能求解一个最优化问题呢?并没有适合所有情况的方法,但贪心选择性质和最优子结构是两个关键要素。
如果我们能够证明问题具有这些性质,就向贪心算法迈出了重要一步。
贪心选择性质第一个关键要素是贪心选择性质(greedy choice property):我们可以通过做出局部最优(贪心)选择来构造全局最优解。
换句话说,当进行选择时,我们直接做出在当前问题中看来最优的选择,而不必考虑子问题的解。