贪心算法概论
五大算法思想—贪心算法
![五大算法思想—贪心算法](https://img.taocdn.com/s3/m/9f120d11bfd5b9f3f90f76c66137ee06eff94e4b.png)
五⼤算法思想—贪⼼算法怎么理解 贪⼼法在解决这个问题的策略上⽬光短浅,仅仅依据当前已有的信息就做出选择,并且⼀旦做出了选择。
⽆论将来有什么结果,这个选择都不会改变。
⼀句话:不求最优,仅仅求可⾏解。
怎样推断 对于⼀个详细的问题,怎么知道是否可⽤贪⼼算法解此问题,以及是否能得到问题的最优解? 我们能够依据贪⼼法的2个重要的性质去证明:贪⼼选择性质和最优⼦结构性质。
1、贪⼼选择 什么叫贪⼼选择?从字义上就是贪⼼也就是⽬光短线。
贪图眼前利益。
在算法中就是仅仅依据当前已有的信息就做出选择,并且以后都不会改变这次选择。
(这是和动态规划法的主要差别) 所以对于⼀个详细问题。
要确定它是否具有贪⼼选择性质,必须证明每做⼀步贪⼼选择是否终于导致问题的总体最优解。
2、最优⼦结构 当⼀个问题的最优解包括其⼦问题的最优解时,称此问题具有最优⼦结构性质。
这个性质和动态规划法的⼀样,最优⼦结构性质是可⽤动态规划算法或贪⼼算法求解的关键特征。
区分动态规划 动态规划算法通常以⾃底向上的⽅式解各⼦问题,是递归过程。
贪⼼算法则通常以⾃顶向下的⽅式进⾏,以迭代的⽅式作出相继的贪⼼选择,每作⼀次贪⼼选择就将所求问题简化为规模更⼩的⼦问题。
以⼆叉树遍历为例: 贪⼼法是从上到下仅仅进⾏深度搜索。
也就是说它从根节点⼀⼝⽓⾛到⿊的,它的代价取决于⼦问题的数⽬,也就是树的⾼度,每次在当前问题的状态上作出的选择都是1。
不进⾏⼴度搜索。
所以终于它得出的解不⼀定是最优解。
⾮常有可能是近似最优解。
⽽动态规划法在最优⼦结构的前提下,从树的叶⼦节点開始向上进⾏搜索,⽽且在每⼀步都依据叶⼦节点的当前问题的状况作出选择,从⽽作出最优决策。
所以她的代价是⼦问题的个数和可选择的数⽬。
它求出的解⼀定是最优解。
⼀般求解过程 使⽤贪⼼法求解能够依据下⾯⼏个⽅⾯进⾏(终于也相应着每步代码的实现),以找零钱为例: 1、候选集合(C) 通过⼀个候选集合C作为问题的可能解。
贪心算法问题解决策略概述
![贪心算法问题解决策略概述](https://img.taocdn.com/s3/m/cb6ff90a0a4c2e3f5727a5e9856a561252d321fd.png)
贪心算法问题解决策略概述贪心算法(Greedy Algorithm)是一种简单而有效的问题解决策略,通过每一步的局部最优选择,最终达到全局最优解。
其基本思想是从问题的某个初始解出发,通过贪心的选择,逐步得到一个更优解,以求解整个问题。
本文将对贪心算法的基本原理以及应用领域进行概述。
一、贪心算法的基本原理贪心算法的核心思想是每一步都做出当前的最优选择,将问题分解为一系列子问题,并进行局部最优解的选择,最终得到全局最优解。
二、适用条件贪心算法适用于具有贪心选择性质的问题,即通过局部最优解可以得到全局最优解。
贪心选择性质是指每一步的选择只依赖于当前状态,不受其他步骤的影响。
三、典型应用1. 最小生成树问题:在一个连通图中,找出一个包含所有顶点的边的子集,使得这个子集形成一个树,且所有边的权值之和最小。
2. 哈夫曼编码问题:在编码问题中,通过给频率较高的字符分配较短的编码,从而使得编码的总长度最短。
3. 区间调度问题:给定一组区间,选择尽量多的互不重叠的区间。
4. 零钱支付问题:给定一定面额的硬币和一个要支付的金额,找出支付方式使得所需硬币的数量最少。
5. 背包问题的一些变体:如01背包问题、完全背包问题等。
四、算法步骤贪心算法的思路是通过局部最优解来构建全局最优解。
其一般步骤如下:1. 建立数学模型来描述问题。
2. 将问题分解为若干个子问题。
3. 对每个子问题求解,得到局部最优解。
4. 对所有子问题的局部最优解进行整合,得到原问题的最优解。
五、优缺点贪心算法的优点在于简单、高效,能够快速地找到一个近似最优解。
但是它也有一些缺点,即不能保证能够得到全局最优解,因为贪心策略是基于局部最优的选择,并不能考虑全局情况。
六、总结贪心算法作为一种简单而有效的问题解决策略,在许多实际问题中发挥着重要作用。
通过每一步的局部最优选择,贪心算法能够快速地找到一个近似最优解。
但需要注意的是,贪心算法并不能保证一定能够得到全局最优解,因此在具体应用中需要谨慎分析问题的特点,判断是否适合采用贪心算法。
贪心算法的概念和适用条件 -回复
![贪心算法的概念和适用条件 -回复](https://img.taocdn.com/s3/m/2e7ba882ba4cf7ec4afe04a1b0717fd5360cb2de.png)
贪心算法的概念和适用条件-回复什么是贪心算法?贪心算法(Greedy Algorithm)是一种以局部最优解为导向的算法思想,通过每一步选择当前状态下的最佳操作来达到整体最优解的目标。
贪心算法的核心思想是每次都做出当前看来最优的选择,以期望能够达到整体的最优解。
贪心算法通常用于一些问题中,即每一步的选择只依赖于当前状态,而不考虑将来可能出现的情况。
贪心算法的适用条件:1. 贪心选择性质:贪心算法每一步都选择一个当前的最优解,此处的“最优”指的是局部最优。
这种最优选择可以确保问题能够被拆解,并且进行下一步求解。
2. 最优子结构性质:当问题的整体最优解能够通过局部最优解得到时,可以采用贪心算法求解。
这种情况下,问题的最优解可以由子问题的最优解推导出来。
3. 无后效性:贪心算法选择某一步操作时,只考虑当前状态,不会改变以前的操作,并且不关心未来的操作。
这种无后效性使得贪心算法在实际应用中操作简单、效率高。
贪心算法的基本步骤:1. 确定问题的局部最优解:贪心算法的核心是每一步都选择在当前情况下的最优解。
因此,需要确定问题如何拆解以及如何进行局部最优选择。
2. 定义问题的子问题:根据问题的最优子结构性质,将问题拆解为较小规模的子问题。
子问题应该是原问题的一个更小、更简单的实例。
3. 定义贪心选择策略:根据问题的特性,确定当前步骤下的最优选择策略。
这个选择应该是局部最优的,可以在不考虑子问题和整体未来状态的情况下得出。
4. 重复执行步骤2和3,直至求解出全局最优解。
贪心算法的优缺点:贪心算法具有简单易懂、快速高效的特点,适用于许多实际问题。
它可以避免穷举所有可能性,节省了计算时间。
此外,贪心算法常常能够找到近似最优解,尽管不一定能够保证全局最优解。
在实际问题中,近似最优解也往往可以满足实际需求。
然而,贪心算法并非适用于所有问题。
由于贪心算法只考虑当前状态的最优选择,而不考虑未来的影响,因此可能会导致局部最优解与全局最优解不一致。
五大常用算法之三:贪心算法
![五大常用算法之三:贪心算法](https://img.taocdn.com/s3/m/b0bf7c1d54270722192e453610661ed9ad515595.png)
五⼤常⽤算法之三:贪⼼算法贪⼼算法的定义:贪⼼算法是指在对问题求解时,总是做出在当前看来是最好的选择。
也就是说,不从整体最优上加以考虑,只做出在某种意义上的局部最优解。
贪⼼算法不是对所有问题都能得到整体最优解,关键是贪⼼策略的选择,选择的贪⼼策略必须具备⽆后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
解题的⼀般步骤是:1.建⽴数学模型来描述问题;2.把求解的问题分成若⼲个⼦问题;3.对每⼀⼦问题求解,得到⼦问题的局部最优解;4.把⼦问题的局部最优解合成原来问题的⼀个解。
如果⼤家⽐较了解动态规划,就会发现它们之间的相似之处。
最优解问题⼤部分都可以拆分成⼀个个的⼦问题,把解空间的遍历视作对⼦问题树的遍历,则以某种形式对树整个的遍历⼀遍就可以求出最优解,⼤部分情况下这是不可⾏的。
贪⼼算法和动态规划本质上是对⼦问题树的⼀种修剪,两种算法要求问题都具有的⼀个性质就是⼦问题最优性(组成最优解的每⼀个⼦问题的解,对于这个⼦问题本⾝肯定也是最优的)。
动态规划⽅法代表了这⼀类问题的⼀般解法,我们⾃底向上构造⼦问题的解,对每⼀个⼦树的根,求出下⾯每⼀个叶⼦的值,并且以其中的最优值作为⾃⾝的值,其它的值舍弃。
⽽贪⼼算法是动态规划⽅法的⼀个特例,可以证明每⼀个⼦树的根的值不取决于下⾯叶⼦的值,⽽只取决于当前问题的状况。
换句话说,不需要知道⼀个节点所有⼦树的情况,就可以求出这个节点的值。
由于贪⼼算法的这个特性,它对解空间树的遍历不需要⾃底向上,⽽只需要⾃根开始,选择最优的路,⼀直⾛到底就可以了。
话不多说,我们来看⼏个具体的例⼦慢慢理解它:1.活动选择问题这是《算法导论》上的例⼦,也是⼀个⾮常经典的问题。
有n个需要在同⼀天使⽤同⼀个教室的活动a1,a2,…,an,教室同⼀时刻只能由⼀个活动使⽤。
每个活动ai都有⼀个开始时间si和结束时间fi 。
⼀旦被选择后,活动ai就占据半开时间区间[si,fi)。
如果[si,fi]和[sj,fj]互不重叠,ai和aj两个活动就可以被安排在这⼀天。
算法设计与分析 第五章 贪心算法
![算法设计与分析 第五章 贪心算法](https://img.taocdn.com/s3/m/c7932543a8956bec0975e369.png)
第五章 贪心算法§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 件物品。
贪心算法概述
![贪心算法概述](https://img.taocdn.com/s3/m/617a865df6ec4afe04a1b0717fd5360cba1a8d81.png)
贪⼼算法概述贪⼼,顾名思义,就是在把⼀个⼤问题分割成⽆数个相类似的⼦结构之后,对于每⼀个⼦结构,只在乎当前,贪⼼考虑最优选择,⽆需考虑整体最优。
⽤专业⼀点的术语来说,就是⽆后效性。
具体来说,⾯对⼀个⼤问题,截取当前的⼀⼩部分,在这个⼩部分中选择最优最好的结果。
然后以⼀种迭代,也就是递推的⽅式选取相似的下⼀⼩部分。
每次⾯对⼀⼩部分问题,保存最好的结果,丢进集合中。
最后在考虑整体的时候,贪⼼的结果就是集合⾥这些每个⼩部分问题保存下来的结果的综合。
贪⼼算法是指在对问题求解时,总是做出在当前看来是最好的选择。
也就是说,不从整体最优上加以考虑,只做出在某种意义上的局部最优解。
贪⼼算法不是对所有问题都能得到整体最优解,关键是贪⼼策略的选择,选择的贪⼼策略必须具备⽆后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
贪⼼算法的基本要素:1.贪⼼选择性质。
所谓贪⼼选择性质是指所求问题的整体最优解可以通过⼀系列局部最优的选择,即贪⼼选择来达到。
这是贪⼼算法可⾏的第⼀个基本要素,也是贪⼼算法与动态规划算法的主要区别。
动态规划算法通常以⾃底向上的⽅式解各⼦问题,⽽贪⼼算法则通常以⾃顶向下的⽅式进⾏,以迭代的⽅式作出相继的贪⼼选择,每作⼀次贪⼼选择就将所求问题简化为规模更⼩的⼦问题。
对于⼀个具体问题,要确定它是否具有贪⼼选择性质,必须证明每⼀步所作的贪⼼选择最终导致问题的整体最优解。
2. 当⼀个问题的最优解包含其⼦问题的最优解时,称此问题具有最优⼦结构性质。
问题的最优⼦结构性质是该问题可⽤动态规划算法或贪⼼算法求解的关键特征。
贪⼼算法的基本思路:从问题的某⼀个初始解出发逐步逼近给定的⽬标,以尽可能快的地求得更好的解。
当达到算法中的某⼀步不能再继续前进时,算法停⽌。
该算法存在问题:1. 不能保证求得的最后解是最佳的;2. 不能⽤来求最⼤或最⼩解问题;3. 只能求满⾜某些约束条件的可⾏解的范围。
实现该算法的过程:从问题的某⼀初始解出发;while 能朝给定总⽬标前进⼀步 do 求出可⾏解的⼀个解元素;由所有解元素组合成问题的⼀个可⾏解;⽤背包问题来介绍贪⼼算法:背包问题:有⼀个背包,背包容量是M=150。
0021算法笔记——【贪心算法】贪心算法与精彩活动安排问题
![0021算法笔记——【贪心算法】贪心算法与精彩活动安排问题](https://img.taocdn.com/s3/m/5e335c29fc4ffe473368ab8a.png)
0021算法笔记——【贪心算法】贪心算法与活动安排问题1、贪心算法(1)原理:在对问题求解时,总是做出在当前看来是最好的选择。
也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题他能产生整体最优解或者是整体最优解的近似解。
(2)特性:贪心算法采用自顶向下,以迭代的方法做出相继的贪心选择,每做一次贪心选择就将所求问题简化为一个规模更小的子问题,通过每一步贪心选择,可得到问题的一个最优解,虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪婪法不要回溯。
能够用贪心算法求解的问题一般具有两个重要特性:贪心选择性质和最优子结构性质。
1)贪心选择性质所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。
这是贪心算法可行的第一个基本要素。
贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。
对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。
证明的大致过程为:首先考察问题的一个整体最优解,并证明可修改这个最优解,使其以贪心选择开始。
做了贪心选择后,原问题简化为规模更小的类似子问题。
然后用数学归纳法证明通过每一步做贪心选择,最终可得到问题的整体最优解。
其中,证明贪心选择后的问题简化为规模更小的类似子问题的关键在于利用该问题的最优子结构性质。
2)最优子结构性质当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。
(3)贪心算法与动态规划算法的差异:动态规划和贪心算法都是一种递推算法,均有最优子结构性质,通过局部最优解来推导全局最优解。
两者之间的区别在于:贪心算法中作出的每步贪心决策都无法改变,因为贪心策略是由上一步的最优解推导下一步的最优解,而上一部之前的最优解则不作保留,贪心算法每一步的最优解一定包含上一步的最优解。
算法导论-贪心算法
![算法导论-贪心算法](https://img.taocdn.com/s3/m/74b1f263cdbff121dd36a32d7375a417866fc10f.png)
贪心算法可以看作是动态规划的一种特例,其中只保 留了与当前状态和当前选择相关的子问题的解,而不
是保留所有子问题的解。
贪心算法通常在每一步选择中只考虑当前状态下的局 部最优解,而不是考虑所有可能的选择和未来的状态。
贪心算法的经述 • 贪心算法的基本思想 • 贪心算法的经典问题 • 贪心算法的实现与优化 • 贪心算法的性能分析 • 总结与展望
贪心算法概述
01
定义与特点
定义
贪心算法是一种在每一步选择中都采取当前情况下最好或最优(即最有利)的 选择,从而希望导致结果是最好或最优的算法。
无法保证全局最优解
贪心算法可能只得到局部最优解,而非全局最 优解。
缺乏理论支持
贪心算法的理论基础尚不完备,难以对所有情况做出准确预测。
贪心算法与其他算法的比较
与动态规划算法比较
动态规划算法通过将问题分解为子问题来求解,适合处理具有重叠子问题和最优子结构的问题;而贪 心算法则是每一步都选择当前最优的选择,希望这样的局部最优选择能够导致全局最优解。
法的时间复杂度。
需要注意的是,贪心算法并不总是能够提供最优解,因此在实际应用中, 需要权衡时间复杂度和解的质量。
空间复杂度分析
贪心算法的空间复杂度主要取决于算法 的存储需求。在某些情况下,贪心算法 可能需要大量的存储空间来存储中间结
果或数据结构。
在分析贪心算法的空间复杂度时,需要 考虑算法所需的存储空间和存储结构的 复杂性。通过将每个存储需求的空间复 杂度相加,可以得出整个算法的空间复
与分治算法比较
分治算法是将问题分解为若干个子问题,然后递归地求解这些子问题,再将子问题的解合并起来得到 原问题的解;而贪心算法是在每一步都做出在当前状态下最好或最优(即最有利)的选择,希望这样 的局部最优选择能够导致全局最优解。
算法设计与分析讲义贪心法
![算法设计与分析讲义贪心法](https://img.taocdn.com/s3/m/5406707d326c1eb91a37f111f18583d049640fe5.png)
贪心算法在每一步选择时都采取在当前状态下最好或最优( 即最有利)的选择,而不考虑可能出现的后果。
贪心算法与动态规划
贪心算法是一种局部最优策略,即每一步选择在当前状态下 是最优的,但不一定能够得到全局最优解。
动态规划是一种全局最优策略,通过将问题分解为子问题, 逐步求解得到全局最优解。
贪心算法的历史与发展
选择适当的贪心策略
选择适当的贪心策略可以最大程度 地减少计算时间。
空间优化
通过优化算法的空间复杂度,减少 算法的空间占用,以提高算法的效 率。
并行计算
利用并行计算技术,将算法并行化 ,以提高算法的运行速度。
数据结构优化
使用合适的数据结构可以加快算法 的执行速度,如哈希表、堆等。
06
贪心算法的应用扩展
贪心算法的优化策略
总结词
记忆化搜索、动态规划优化、全局状态决策
详细描述
贪心算法虽然能够得到问题的近似解,但在某些情况 下可能无法得到最优解。为了提高贪心算法的性能, 可以采用一些优化策略,例如记忆化搜索,将已经计 算过的状态存储下来,避免重复计算;动态规划优化 ,将问题分解为子问题,通过解决子问题来解决原问 题;全局状态决策,将问题的所有状态作为一个整体 来考虑,利用问题的整体性质来得到更好的解。
在资源分配问题中,贪心算法可以用于求解具有单位资源的最大权值
组合问题、分数背包问题等。
05
贪心算法的实现技巧
贪心算法的编程实现
确定贪心策略
根据问题特性确定贪心策略,通常选择最优解或近似最优解。
编码实现
将贪心策略转化为代码实现,通常使用循环和条件语句实现算 法。
测试样例
设计测试样例,覆盖各种情况,提高算法的健壮性和正确性。
贪心算法讲义
![贪心算法讲义](https://img.taocdn.com/s3/m/e2fbb87f551810a6f424868e.png)
float p[1..n], w[1..n], x[1..n], M, rc;
integer i, n; x:= 0; // 将解向量初始化为零
//w[1..n],它们元素的排列 //顺序满p[i]/w[i]≥p[i+1]/w[i+1] //M是背包容量,x[1..n]是解向量
rc:= M; // 背包的剩余容量初始化为M
作业调度问题
单机作业调度问题的贪心算法
将上述算法找到的作业集按作业期限升序排列,就产生一 个作业调度。
算法的复杂度分析
J {i}的相容性判断最坏|J|次,|J|最大i-1。所以 T(n)=1+2+…+n-1=O(n2)
例子: 设n=7,
(p1, p2,… ,pn)=(35,30,25,20,15,10,5), (d1, d2,… ,dn)=(4,2,4,3,4,8,3) 算法GreedyJob的执行过程 : 作业 1 ;2, 1; 2, 1, 3; 2, 4, 1, 3; 2, 4, 1, 3 , 6; 期限 4; 2, 4; 2,4, 4; 2, 3, 4, 4; 2, 3, 4, 4, 8;
带期限的单机作业安排问题
已知n项作业 E={1, 2, … ,n}要求使用同台机器完成, 而且每项作业需要的时间都是1。第k项作业要求在时 刻2, d…k之, n前。完成, 而且完成这项作业将获得效益pk,k=1,
作业集E的子集称为相容的如果其中的作业可以被安 排由一台机器完成。
带限期单机作业安排问题就是要在所给的作业集合中 选出总效益值最大的相容子集。
许多NP难组合优化问题,目前仍未找到有效的算法, 贪心策略常用于设计这些问题的近似算法。
贪心算法的基本思想
第7章 贪心算法
![第7章 贪心算法](https://img.taocdn.com/s3/m/d951111f227916888486d78a.png)
为了得到最大值,设置控制n-1次操作的k (1——n-1)循环。每次操作对最小的前2 项 a[k]、a[k+1]实施操作: x=a[k];y=a[k+1];a[k+1]=x*y+1; 操作后,应用逐项比较对a[k+1],„,a[n]进 行升序排列,为下一次操作做准备。 最后所得a[n]即为所求的数列操作的最大值。 因应用逐项比较进行排列,其时间复杂度为 O(n^2),因而数列操作的贪心设计的时间复杂度 为O(n^3)。
1. 哈夫曼算法要点
1) 首先,对给定的n个权值作升序排列。 2) 设置n-1次操作的k(1——n-1)循环,在第k次操 作中,由两个最小权值叶结点生成一个新结点: x=w[2*k-1]; y=w[2*k]; w[n+k]=x+y; lc[n+k]=x; rc[n+k]=y; 3) 新结点参与排序,为下一次操作做准备。 考虑到每一次排序可能改变w数组元素顺序,设置u数 组,每次所得新结点,其数据传送给u数组,最后输出时 不是按已改变次序的w数组,而是按u数组输出。 4) 为具体画出哈夫曼树提供方便,输出展示每一个 结点的左右子结点的表。
wpl l (k ) w(k )
k 1
n
7.6 哈夫曼树及其应用
7.6.1 哈夫曼树
设二叉树共有n个端点,从二叉树第k个端点到树的根 结点的路径长度l(k)为该端结点(或叶子)的祖先数,即 该叶子的层数减1。同时,每一个结点都带一个权(实 数),第k个端点所带权为w(k)。定义各个端结点的路径 长l(k)与该点的权w(k)的乘积之和为该二叉树的带权路径 长,即 对n个权值w(1),w(2),„,w(n),构造出所有由n个分别 带这些权值的叶结点组成的二叉树,其中带权路径长wpl 最小的二叉树称为哈夫曼树。
贪心算法总结
![贪心算法总结](https://img.taocdn.com/s3/m/d87937488f9951e79b89680203d8ce2f00666519.png)
贪心算法总结什么是贪心算法?贪心算法(Greedy Algorithm)是一种用于求解优化问题的常见算法,其核心思想是在每一步都选择当前最优解,希望最终能够得到全局最优解。
贪心算法在每一步仅考虑局部最优,而不关心全局最优,因此它的计算速度较快。
然而,由于贪心算法没有考虑全局,在某些情况下可能无法得到最优解。
贪心算法并不适用于所有的问题,只适用于一些特殊的问题,例如背包问题、最小生成树问题等。
在实际应用中,需要根据具体问题的特点来判断是否可以使用贪心算法来解决。
贪心算法的基本思路贪心算法的基本思路可以概括为以下几步:1.确定最优解的性质:首先要确定在每一步选择中,能够得到局部最优解。
2.构造贪心选择:根据最优解的性质,每一步都做出一个贪心选择,选择能够获得当前最大或最小收益的方案。
3.确定限制条件:确定问题的限制条件,包括物品的容量、时间限制等。
4.根据限制条件,进行剪枝策略:如果某种选择在限制条件下无法满足要求,则需要进行剪枝,排除该选择。
5.循环执行贪心选择,直到问题得到解决。
贪心算法的优缺点贪心算法具有以下优点:•计算速度快:贪心算法在每一步只考虑局部最优解,不需要对全局进行搜索,因此计算速度较快。
•算法思路简单:贪心算法的思路相对简单,易于理解和实现。
•适用范围广:贪心算法适用于一些特殊问题,如最短路径、最小生成树等。
然而,贪心算法也存在一些缺点:•可能无法得到最优解:由于贪心算法仅考虑局部最优解,而不关心全局最优解,因此可能无法得到最优解。
•需要满足贪心选择性质:贪心算法要求问题具有贪心选择性质,即每一步都能够得到局部最优解。
如果问题不具备这个性质,贪心算法可能不适用。
贪心算法的应用场景贪心算法适用于一些特殊的问题,以下是一些常见的应用场景:1. 最短路径问题最短路径问题是指在一个加权有向图中,找出从一个顶点到另一个顶点的最短路径。
贪心算法可以用来解决一些简单的最短路径问题,如Dijkstra算法。
贪心算法的理解-概述说明以及解释
![贪心算法的理解-概述说明以及解释](https://img.taocdn.com/s3/m/e94a3054a66e58fafab069dc5022aaea998f41ad.png)
贪心算法的理解-概述说明以及解释1.引言1.1 概述概述部分的内容可以描述贪心算法的基本概念和作用。
贪心算法是一种常用的求解优化问题的算法思想,其核心思想是在每一步都选择当前最优解,从而希望最终达到全局最优解。
贪心算法通常适用于那些具有最优子结构特性和贪心选择性质的问题。
具体来说,贪心算法通常分为以下几个步骤:首先,根据问题的特性确定问题的目标函数或者判断问题的可行解的标准;其次,把原问题分解为若干个子问题,每次选择最优解作为当前问题的解;接着,对所选取的解进行判断,如果满足问题的约束条件,则放入解集中,否则舍弃;最后,递归或者迭代地处理下一个子问题,直到找出全局最优解。
贪心算法的应用非常广泛,它可以用来解决许多实际问题,比如最小生成树、最短路径、背包问题等。
贪心算法的优点在于简单、高效,其时间复杂度通常较低。
然而,贪心算法也有其局限性,它只关注当前的最优解而不考虑全局的最优解,因此在某些问题上可能会得到次优解甚至是错误的解。
综上所述,贪心算法是一种重要的优化算法思想,通过不断选择当前最优解来求解问题。
它的应用广泛,具有高效简单的特点,但也存在局限性。
在今后的发展中,我们可以对贪心算法进行改进,使其在更多的问题中发挥更强大的作用。
1.2 文章结构文章结构部分:本文分为引言、正文和结论三个部分。
引言部分主要概述了本文的主题——贪心算法,并介绍了文章的结构和目的。
正文部分将重点讲解贪心算法的定义、原理、应用场景以及优缺点。
首先,在2.1节中,我们将介绍什么是贪心算法。
贪心算法是一种在每一步选择中都选择当前情况下最好或最优的选择,以期望能够导致全局最优解的算法。
其次,在2.2节中,我们将详细解析贪心算法的原理。
贪心算法的核心思想是通过不断地做出局部最优选择,从而最终得到全局最优解。
我们将使用一些具体的示例来说明贪心算法的运作方式。
然后,在2.3节中,我们将探讨贪心算法的应用场景。
贪心算法在很多实际问题中都有广泛的应用,如任务调度、背包问题、最短路径等。
贪 心 算 法
![贪 心 算 法](https://img.taocdn.com/s3/m/8b2209b12af90242a895e5cc.png)
贪心算法1:贪心的概念最优装载问题贪心算法的原理:贪心算法总是做出当前最好的选择,也就是说,它期望通过局部最优选择从而得到全局最优的解决方案。
1. 没有后悔药,一旦做出选择,不可以后悔;2. 有可能得到的不是最优解,而是最优解的近似解。
3. 选择什么样的贪心策略,直接决定算法的好坏。
贪心策略的基本思想定义:贪心法是一种解决最优问题的策略。
它是从问题的初始解出发,按照当前最佳的选择,把问题归纳为更小的相似的子问题,并使子问题最优,再由子问题来推导出全局最优解。
使用贪心方法需要注意局部最优与全局最优的关系,选择当前状态的局部最优并不一定能推导出问题的全局最优。
贪心算法求解的三个步骤:a、确定贪心策略b、根据贪心策略,一步一步得到局部最优解c、将局部最优解合并起来就得到全局最优解贪心策略的特点1.贪心选择性质:所求问题的整体最优解可以通过一系列局部最优的选择来达到,这样的选择称为贪心选择。
这些选择只依赖于以往所做过的选择,决不依赖于将来的选择。
2.最优子结构性质:当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。
例题说明:例题:有一个3*3的方格,每个格子有一个正整数,要求从每行格子中取一个数,使得取出来的3个数字之和最大(贪心)。
题目修改:规定从左下角出发,每次只能向上或向右移动一格,现在要求找出一条路径使得从左下角到达右上角所经过的格子中的数字之和最大,求最大值。
贪心方法:3→14→12→5→8=42(每次都找向上或者向右最大的一个)最优解:3→6→20→9→8=46局部最优无法带来全局最优,这就是不具备贪心选择性质。
什么样的问题能用贪心来求解:利用贪心算法求解的问题往往具有两个重要的特性:贪心选择性质和最优子结构性质。
(1)贪心选择所谓贪心选择性质是指原问题的整体最优解可以通过一系列局部最优的选择得到。
(2)最优子结构当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。
贪心算法
![贪心算法](https://img.taocdn.com/s3/m/d5d2196db307e87100f69619.png)
第一行有2个正整数n (1<n<=200)和m (m<=1000),表示有N个城市和M条SARS。
接下来的行是三个正整数StartCity,EndCity,speed,表示从表面上看StartCity到EndCity,限速为speedSARS。speed<=1000000 然后是一个正整数Q(Q<11),表示寻路的个数。 接下来Q行每行有2个正整数Start,End, 表示寻路的起终点。 Output 每个寻路要求打印一行,仅输出一个非负整数表示最佳路线的舒适度最高速与最低速的差。如果起点和终点不能到达,那么输出 -1。
2、结点的权及带权路径长度
若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点 的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。 3、树的带权路径长度 树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL
Huffman Tree
多叉哈夫曼树编辑 哈夫曼树也可以是k叉的,只是在构造k叉哈夫曼树时需要先进行一些调整。 构造哈夫曼树的思想是每次选k个权重最小的元素来合成一个新的元素,该 元素权重为k个元素权重之和。但是当k大于2时,按照这个步骤做下去可能 到最后剩下的元素少于k个。解决这个问题的办法是假设已经有了一棵哈夫 曼树(且为一棵满k叉树),则可以计算出其叶节点数目为(k-1)nk+1,式子中的 nk表示子节点数目为k的节点数目。于是对给定的n个权值构造k叉哈夫曼树 时,可以先考虑增加一些权值为0的叶子节点,使得叶子节点总数为(k1)nk+1这种形式,然后再按照哈夫曼树的方法进行构造即可。
贪心大法好
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来 是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某 种意义上的局部最优解。 贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择, 选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后 的状态,只与当前状态有关。 from
贪心算法(Greedy)
![贪心算法(Greedy)](https://img.taocdn.com/s3/m/4c1d000b76c66137ee0619f6.png)
例如, 例如,设7个独立作业{1,2,3,4,5,6,7}由3台 机器M1,M2和M3加工处理。各作业所需的处理时 间分别为{2,14,4,16,6,5,3}。按算法greedy greedy产生 greedy 的作业调度如下图所示,所需的加工时间为17。
约定,每个作业均可在任何一台机器上加工处理, 约定,每个作业均可在任何一台机器上加工处理,但未 完工前不允许中断处理。作业不能拆分成更小的子作业。 完工前不允许中断处理。作业不能拆分成更小的子作业。
采用最长处理时间作业优先 最长处理时间作业优先的贪心选择策略可以设计 最长处理时间作业优先 出解多机调度问题的较好的近似算法。 按此策略,当 n ≤ m时,只要将机器i的[0, ti]时间区间 分配给作业i即可,算法只需要O(1)时间。 i O(1) 当 n > m 时,首先将n个作业依其所需的处理时间从大 到小排序。然后依此顺序将作业分配给空闲的处理机。算 法所需的计算时间为O(nlogn)。
void Knapsack(int n,float M,float Knapsack(int v[],float w[],float x[]) { Sort(n,v,w); int i; for (i=1;i<=n;i++) x[i]=0; float c=M; for (i=1;i<=n;i++) { if (w[i]>c) break; x[i]=1; c-=w[i]; } if (i<=n) x[i]=c/w[i]; }
用贪心算法解背包问题的基本步骤:
首先计算每种物品单位重量的价值Vi/Wi,然后,依贪心 首先计算每种物品单位重量的价值Vi/Wi,然后,依贪心 选择策略,将尽可能多的单位重量价值最高 选择策略,将尽可能多的单位重量价值最高的物品装入背包。 单位重量价值最高的物品装入背包。 若将这种物品全部装入背包后,背包内的物品总重量未超过 C,则选择单位重量价值次高的物品并尽可能多地装入背包。 依此策略一直地进行下去,直到背包装满为止。 具体算法可描述如下页:
算法分析与设计实验二贪心算法
![算法分析与设计实验二贪心算法](https://img.taocdn.com/s3/m/14d5cdab6394dd88d0d233d4b14e852458fb3917.png)
算法分析与设计实验二贪心算法贪心算法(Greedy Algorithm)是一种常用的算法设计方法,其核心思想是在每一步都做出当前情况下最优选择,以期望最终得到全局最优解。
本实验主要介绍贪心算法的原理、应用和分析。
一、贪心算法的原理贪心算法的基本思路是在每一步都做出当前情况下最优选择,并且不考虑当前选择对后续选择的影响。
贪心算法通常采用贪心选择策略和最优子结构两个基本要素。
1.贪心选择策略贪心选择策略是指在每一步都选择当前情况下最优解的策略。
这种策略要求我们能够证明,通过选择当前最优解,可以使得问题的规模减小到原问题的一个子问题,并且该子问题的最优解一定包含在全局最优解中。
2.最优子结构最优子结构是指问题的最优解包含其子问题的最优解。
贪心算法求解问题的过程通常包括两个步骤,选择最优子结构和利用最优子结构得到最优解。
二、贪心算法的应用1.集合覆盖问题集合覆盖问题是指在给定的一组集合中,找出最小的子集合,使得这些子集合的并集包含所有的元素。
贪心算法可以通过每一步选择包含最多未覆盖元素的集合,直到覆盖所有元素为止。
2.挑选活动问题挑选活动问题是指在给定一组活动的起始时间和结束时间,找出最大的相容活动子集合。
贪心算法可以通过每一步选择结束时间最早的活动,之后将该活动与其他相容的活动进行比较,从而得到最大的相容活动子集合。
3.分数背包问题分数背包问题是指在给定一组物品和一个背包容量的情况下,选择部分物品放入背包,使得放入背包的物品总价值最大。
贪心算法可以通过每一步选择单位重量价值最高的物品,直到背包容量不足为止。
三、贪心算法的分析贪心算法通常具有高效性和近似最优性的特点。
由于贪心算法每一步都选择当前最优解,不进行回溯和剪枝的操作,因此贪心算法的时间复杂度较低。
然而,贪心算法并不总能得到问题的最优解,它通常只能得到近似最优解。
贪心算法的近似性证明可以分为两步。
首先,我们需要证明贪心选择策略的正确性,即每一步选择的最优解一定包含在全局最优解中。
算法导论-贪心算法
![算法导论-贪心算法](https://img.taocdn.com/s3/m/f125a40bf111f18583d05adc.png)
算法导论——贪心算法求解最优化问题的算法通常需要经过一系列的步骤,在每个步骤都面临多种选择。
对于许多最优化问题,使用动态规划算法来求最优解有些杀鸡用牛刀了,可以使用更简单、更高效的算法。
贪心算法(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)中固有的考查所有选择的过程。
实际上,对于活动选择问题,我们只需考虑一个选择:贪心选择。
对于活动选择问题,什么是贪心选择?直观上,我们应该选择这样一个活动,选出它后剩下的资源应能被尽量多的其他任务所用。
浅析贪心算法
![浅析贪心算法](https://img.taocdn.com/s3/m/b4edb27627284b73f24250d5.png)
浅析贪心算法摘要:本文首先概述了贪心算法,然后探讨并研究了贪心算法的基本思想及实现过程,通过实例分析了贪心算法的具体应用,指出了贪心算法的特点及存在问题。
关键词:贪心算法;贪心策略;最优解;穿墙问题为了满足人们对大数据量信息处理的渴望,为解决各种实际问题,计算机算法学得到了飞速的发展,线性规划、动态规划、贪心策略等一系列运筹学模型纷纷运用到计算机算法学中,产生了解决各种现实问题的有效算法。
当一个问题具有最优子结构性质和贪心选择性质时,贪心算法通常会给出一个简单、直观和高效的解法。
一.贪心算法的概述1.1 贪心算法的定义贪心算法(greedy algorithm,又称贪婪算法)是一种能够得到某种度量意义下的最优解的分级处理方法,它总是做出在当前看来是最优的选择,也就是说贪心策略并不是从整体上加以考虑,它所做出的选择只是在某种意义上的局部最优解算法。
贪心策略是最接近人类认知思维的一种解题策略,贪心策略是指从问题的初始状态出发,通过若干次的贪心选择而得出最优值(或较优解)的一种解题方法。
贪心算法就是从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快地求得更好的解。
当达到某算法中的某一步不能再继续前进时,算法停止。
这时就得到了问题的一个解,但不能保证求得的最后解是最优的做一种目前最贪婪的行动。
贪心法和递推法有相似之外,也是从问题的某一个初始解出发,向给定的目标递推,但不同的是每一步不是依据某一个固定的递推式,而是做一个当时看似最佳的贪心选择,不断地将问题归结为更小的相似的问题。
1.2 贪心算法的基本思想用局部解构造全局解,即从问题的某一个初始解逐步逼近给定的目标,以尽可能快地求得更好的解。
当某个算法中的某一步不能再继续前进时,算法停止。
贪心算法思想的本质就是分治,或者说:分治是贪心的基础。
每次都形成局部最优解,换一种方法说,就是每次都处理出一个最好的方案。
利用贪心策略解题,需要解决两个问题:(1)该题是否适合于用贪心策略求解;(2)如何选择贪心标准,以得到问题的最优/较优解。
算法_贪心算法
![算法_贪心算法](https://img.taocdn.com/s3/m/142b24d3d15abe23482f4db2.png)
贪心算法例子:设计一个算法, 把一个真分数表示为埃及 分数之和的形式。所谓埃及分数,是指分子为1的分数。如: 7/8=1/2+1/3+1/24。 基本思想:逐步选择分数所包含的最大埃及分数,这些埃及 分数之和就是问题的一个解。 如:7/8>1/2, 7/8-1/2>1/3, 7/8-1/2-1/3=1/24。 过程如下: 1)找最小的n(最大的埃及分数1/n),使分数f>1/n; 2)输出1/n; 3)计算f=f-1/n; 4)若此时的f是埃及分数,输出f,算法结束,否则返回1)。
物品2 1
物品3 1/2
计算器 24+15*(1/2) = 31.5
• 啄木鸟算盘ห้องสมุดไป่ตู้策略的时间复杂度? O(n2)
第一步:选出单位重量价值最高者装入。 n个中取最大值 第二步:删除该物品。 O(n)
O(n)
第三步:重复1,2步,直至再装入就超出背包的载重量为止。
第四步:把最后选择物品的一部分装入背包:
例5.1 删除数字问题 • 键盘输入一个高精度的正整数N,去掉其中任意S 个数字后剩下的数字按原左右次序将组成一个新 的正整数。编程对给定的N和S,寻找一种方案使 得剩下的数字组成的新数最小。输出应包括所去 掉的数字的位置和组成的新的正整数(N不超过100 位)。 • 数据结构设计:将输入的高精度数存储为字符串 格式。
•
else if (a[j]>a[s2])
s2=j;
max2(int a[],int n) { int j; if(a[1]>=a[2]) { s1=1; s2=2;} else { s1=2; s2=1;} for (j=3;j<=n;j++) { if (a[j]>a[s1]) { s2=s1; s1=j;} else if (a[j]>a[s2]) s2=j; } } int calculatemin(int a[],int n) { int j; while (n>2) { max2(a,n); a[s1]= a[s1]* a[s2]+1; a[s2]=a[n]; n=n-1;} return(a[1]* a[2]+1); }
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
贪心算法概论贪心算法一般来说是解决“最优问题”,具有编程简单、运行效率高、空间复杂度低等特点。
是信息学竞赛中的一个有为武器,受到广大同学们的青睐。
本讲就贪心算法的特点作些概念上的总结。
一、贪心算法与简单枚举和动态规划的运行方式比较贪心算法一般是求“最优解”这类问题的。
最优解问题可描述为:有n个输入,它的解是由这n 个输入的某个子集组成,并且这个子集必须满足事先给定的条件。
这个条件称为约束条件。
而把满足约束条件的子集称为该问题的可行解。
这些可行解可能有多个。
为了衡量可行解的优劣,事先给了一个关于可行解的函数,称为目标函数。
目标函数最大(或最小)的可行解,称为最优解。
a)求“最优解”最原始的方法为搜索枚举方案法(一般为回溯法)。
除了极简单的问题,一般用深度优先搜索或宽度优先搜索。
通常优化方法为利用约束条件进行可行性判断剪枝;或利用目标函数下界(或上界),根据当前最优解进行分枝定界。
b)其次现今竞赛中用的比较普遍的动态规划(需要满足阶段无后效性原则)。
动态规划主要是利用最最优子问题的确定性,从后向前(即从小规模向大规模)得到当前最优策略,从而避免了重复的搜索。
举例说明:求多段图的最短路径。
在图(1)中,我们省略了各线段的长度。
如果用回溯法,搜索树大致如下:显然,上面的搜索有大量重复性工作。
比如节点8、9、10到11的最短路分别被调用了9次,从节点5、6、7到节点11也分别搜索了3次。
如果先算出节点8、9、10到11的最短路,由于它与前面的点无关,因此最优值确定下来,再用它们求定节点5、6、7 到节点11 的最短路径。
同理,再用节点5、6、7 的最优值,来求节点2、3、4 优值。
最后从节点2、3、4 推出1 到11的最优值。
显然复杂度大为降低。
当然,如果本题把简单搜索改为搜索+记忆化的方法,则就是得能动态规划的原理,本质上就是动态规划,只是实现的方法不同与传统的表格操作法。
搜索+记忆化算法有其特有的特点,以后再讨论。
c)贪心算法则不同,它不是建立在枚举方案的基础上的。
它从前向后,根据当前情况,“贪心地”决定出下一步,从而一步一步直接走下去,最终得到解。
假如上面的例子中,我们定下这样的贪心策略:节点号k%3= =1。
则有图3:显然,它只访问了节点1、4、7、10、11,工作量最少,效率最高。
当然,对本题来说,它不能得到最优解―――最短路径。
从图3中可以看出,贪心算法是一种比动态规划更高效的算法。
只是要保证得到最优解是贪心算法的关键。
贪心算法的一般框架为:Procedure Greedy(A,n)//A问题有n个输入BeginInit(ans) //初始化for i:=1 to n donow=select(A) //按设计的标准选取一个“节点”delete(A,now) //把A中的now删掉if can(ans,now) then unio(ans,now) //如果可行性通过,放入解中。
end forend;二、贪心算法的关键――――正确性证明动态规划要满足最优子结构原则,贪心算法呢?就目前的资料看,有个证明模型是“矩阵胚理论”,但要证明一个问题是矩阵胚,十分困难。
并且也不常见的可用贪心算法问题都能用矩阵胚来证明。
因此,可以认为贪心算法的正确性证明是个难点。
因此有些选手在没能证明时,也大胆设想结论应该是正确的。
有时这难免会放错。
例如95年NOI中的“石子合并”一题:例一、石子合并试题:在一个圆形操场的四周摆放N 堆石子(N≤100),现要将石子有次序地合并成一堆。
规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
编一程序,由文件读入堆数N 及每堆石子数(≤20)选择一种合并石子的方案,使得做N-1 次合并,得分的总和最小;选择一种合并石子的方案,使得做N-1 次合并,得分的总和最大。
例如,图4所示的4堆石,每堆石子数(从最上面的一堆数起,顺时针数)依次为4594。
则3次合并得分总和最小的方案为图5,得分总和最大的方案为图6。
输入数据文件名由键盘输入,该文件内容为:第1行为石子堆数N;第2行为每堆石子数,每两个数之间用一个空格符分隔。
输出数据输出文件名为output.txt ;从第1 至第N 行为得分最小的合并方案。
第N+1 行是空行。
从第N+2 行 到第2N+1行是得分最大合并方案。
每种合并方案用N 行表示,其中第i 行(1≤i ≤N)表示第i 次合并前各堆石 子数(依顺时针次序输出,哪一堆先输出均可)。
要求将待合并的两堆石子数以相 应的负数表示,以便标识。
输入输出示例:当时这题是第一次出现,几乎有半数以上人都选择了贪心算法―――每次选 相邻和最小的两堆石子合并。
其实由于只能是相邻的两堆石子合并,并不能套用经典的哈夫曼树算法。
本 题给的样例数据实际上是一个“陷阱”,造成了用贪心法即可解决的假象。
当一个贪心算法不能确定其正确性时,在使用之前,应该努力去证明它的不 正确性。
而要证明不正确性,一种最简单的形式就是举一个反例。
本例的反例见 图7。
常见的证明方法:贪心算法的正确性证明虽然不容易,但一些常见的方法还是值得总结的。
a) 构造法贪心算法的最小值为: (2+3)=5 (4+5)=9 (4+5)=9 (9+6)=15 (15+9)=245+9+9+15+24=62另一种方法的最小值为: (2+4)=6 (3+4)=7 (5+6)=11 (7+6)=13 (11+13)=246+7+11+13+24=61根据描述的算法,用贪心的策略,依次构造出一个解,可证明一定是合法的解。
即用贪心法找可行解。
b) 反证法用贪心的策略,依次构造出一个解S1。
假设最优解S2不同与S1,可以证明是矛盾的。
从而S1就是最优解。
c) 调整法用贪心的策略,依次构造出一个解S1。
假设最优解S2不同与S1,找出不同之处,在不破坏最优性的前提下,逐步调整S2,最终使其变为S1。
从而S1也是最优解。
下面分别举例说明。
例2 士兵排队问题(1996 年中国队选拔赛)----构造法证明试题:有N 个士兵(1≤N≤26),编号依次为A,B,C,...。
队列训练时,指挥官要把一些士兵从高到矮依次排成一行,但现在指挥官不能直接获得每个人的身高信息,只能获得“P1比P2高”这样的比较结果(P1,P2∈A,B,C,...,Z,记为P1>P2),如“A>B”表示A 比B高。
请编一程序,根据所得到的比较结果求出一种符合条件的排队方案。
注:比较结果中没有涉及到的士兵不参加排队输入数据比较结果从文本文件中读入(文件名由键盘输入),每个比较结果在文本文件中占一行。
输出要求若输入数据无解,打印“No Answer!”信息,否则从高到矮依次输出每一个士兵的编号,中间无分隔符,并把结果写入文本文件中,文件名由键盘输入。
输入输出示例INPUT.TXT OUTPUT.TXTA>B AFBDB>DF>D显然用每次选“偏序中最高士兵”的贪心算法就可构造出一个可行解。
这个问题转就是“拓扑排序”问题。
可这样证明:如果有解,就一定无环,因此每步贪心都一定能进行下去。
经典的“找欧拉回路”问题也类似。
例3 排队问题----反证法证明试题:在一个超市,有N 个人排队到一个柜台付款,已知每个人需要处理的时间为Ti(0<i≤N),请你找一种排列次序,使每个人排队的时间总和最小。
输入数据文本文件中第一行为一个正整数N≤10000,第二行有N个不超过1000的正整数Ti。
输出要求只一个正整数:大家排队时间的最小总和。
输入输出示例INPUT.TXT OUTPUT.TXT4 675 10 8 7本题的贪心算法为:N个数据从小到大排序,就是这N个人的最佳排序方案。
求部分和的和即可得到答案。
反证法证明如下:假设有最优解序列S1,S2,S3….,Sn,如果S1 不是最小的Tmin,不妨设Sk=Tmin,将S1 与Sk对调。
显然对Sk之后的人没影响,对Sk之前的人等待时间都减少了(S1-Sk)>0。
从而新的序列比原最优解序列好,矛盾!固S1为最小时间。
同理可证S2是第二小的数,……。
证毕。
下面的调整法也有类似的思想,只是侧重点在“这样调整不会差”。
例4 切巧克力问题----调整法证明试题我们提供给你一块m*n 的巧克力(如图8 所示),你需要将这块巧克力切割成1*1 的单位巧克力。
具体来说,对于一块巧克力,你有两种切割的方法。
一种是沿着某条竖线将巧克力切成两块,另外一种自然是沿着某条横线将巧克力切成两块。
切割需要一定的花费,费用的计算与所切割的巧克力的大小没有关系,而只于沿着哪条线切割有关。
我们将沿着横线切割的费用定义为y1、y2、……、y m-1;同样的,将沿着竖线切割的费用定义为x1、x2、……、x n-1。
现在,需要你计算的就是,怎样切才能使总费用最少?在图8 中,如果我们先沿着横线将整块巧克力切成四块,然后对于每一小块,分别沿着竖线切割,那么总共的费用就是y1+ y 2+ y3+ ( x1+ x2+ x3+ x4) ⨯ 4。
【输入格式】输入文件chocolate.in 的第一行包含两个整数n,m(1 ≤ n,m ≤ 1000),表示巧克力的大小。
接下来的n-1行每行包含一个整数,分别表示沿竖线切割的费用(上图中x1,x2,……),接下来的m-1行也是每行包含一个整数,表示沿横线切割的费用(上图中的y1,y2,……)【输出格式】输出文件chocolate.out 应该包含一个整数,表示你得到的最小切割费用。
样例输入样例输出6 4 4221314412分析:不妨设,Xi已经从大到小排序;Yi也同样。
如果把问题简化,只有横的切Xi或只有竖的切Yi,则显然和排队问题是一样的,可以用贪心算法。
横、竖可以交错切呢?对任意一种方案,只看其中横切的Xi 序列,如果不是从大到小排列,找到第一个违反有序原则的,设为Xp,找出应该在这个位置的――即后面不小于Xp的Xq,把Xp与Xq对调,显然新方案会更好。
如此,有结论一:任意最优方案在不改变竖切次序前提下,可调整成横切是有序的最优解。
同理,有结论二:任意最优方案在不改变横切次序前提下,可调整成竖切是有序的最优解。
综合结论一和结论二,有结论三:任意一种最优方案,可调整成横切、竖切都有序的最优解。
如此,可简单得到动态规划算法,时空复杂度约为O(106)。
上面虽然用了贪心算法的反证法解决了问题,但没有将贪心算法思想进行到底。
我们可以进一步用调整法和反证法的思想,将最优解调整到不分横切、竖切,都是递减的。
简单证明如下:设有最优方案序列XY[1..n+m],序列中任意两相邻项XY[i]和XY[i+1],记为a和b,若a≤b,分三种情况考虑:(1) 若a、b同是横切,显然交换a、b不影响最优解;(2) 若a、b同是竖切,显然交换a、b也不影响最优解;(3) a和b不同,最交换a、b后,增加费用a,减少费用为b,共增加费用为(a-b) ≤0,不会破坏最优性。