如何证明贪心算法
关于贪心算法的正确性证明
“贪心选择性质”的证明下面用数学归纳法给出一个简单的证明。
我们对算法所做的选择步数进行归纳,证明对任意正整数k,算法的前k步选择都能导致一个最优解.定理算法Select执行到第k步,选择k项活动=1,,…,那么存在最优解A包含=1,,…。
证将S中的活动按照截止时间递增顺序排列.归纳基础:k=1时,算法选择了活动1.我们仅需要证明:存在一个最优解包含了活动1.设A{ ,,…,}是一个最优解,如果i11,那么用1替换,得到A’,即A’=(A-{ }){1}那么A’和A的活动个数相等。
且活动1比i1结束的更早,因此和,,…,等活动都相容。
于是A’也是问题的一个最优解.归纳步骤:假设对于任意正整数k,命题正确.令=1,,…是算法前k 步顺序选择的活动,那么存在一个最优解A={=1,,…}B如果令S’是S中剩下的与i1,i2,…,ik相容的活动,即S’={j|, j S}那么B是S’的一个最优解,如若不然,假如S’有解B’,| B’|>|B|,那么用B’替换B以后得到的解{=1,,…}B’将比A的活动更多,与A是最优解矛盾.根据对归纳基础的证明,算法第一步选择结束时间最早的活动总是导致一个最优解,故对子问题S’存在一个最优解B*={,…}.由于B*与B都是S’的最优解,因此| B*|=|B|.于是A’={ =1,,…} B*={=1,,…,}(B*-{ ik+1})与A的活动数目一样多,也是一个最优解,而且恰好包含了算法前k+1步选择的活动。
根据归纳法命题得证.定理告诉我们,算法前k步的选择都将导致最优解,其中k=1,2,….因为至多有n项活动,被选择的活动个数不会超过n,因此算法至少在n步内结束,结束时得到的就是问题的最优解.例有集装箱1,2,…,n准备装上轮船。
其中集装箱i的重量是C,且对集装箱无体积限制。
问如何选择而使得装上船的集装箱个数最多设=1表示第i个集装箱可以装上船,否则=0,则这个问题可以描述为:maxC=0,1 i=1,2,…,n这是一个整数规划问题,也是0-1背包问题的特殊情况.对于0-1背包问题可以使用动态规划算法求解.但是对于这个问题有更好的算法——贪心法.贪心选择策略非常简单,就是“轻者先装”,直到再装任何集装箱将使轮船载重量超过C是停止.算法 Loading输入:集装箱集合N={1,2,…,n},集装箱i的重量 ,i=1,2,…,n输出:I N,准备装入船的集装箱集合1.对集装箱重量排序,使得2.I{1}3.W4.for j 2 to n do5. if W + C6. Then W W+7. I I{j}8. else return I,W算法的时间主要是行1的排序时间O(nlogn),行4的for循环总计执行O(n)时间,于是算法的时间复杂度是O(nlogn)。
贪心算法 实验报告
贪心算法实验报告贪心算法实验报告引言:贪心算法是一种常用的算法设计策略,它通常用于求解最优化问题。
贪心算法的核心思想是在每一步选择中都选择当前最优的解,从而希望最终能够得到全局最优解。
本实验旨在通过实际案例的研究,探索贪心算法的应用和效果。
一、贪心算法的基本原理贪心算法的基本原理是每一步都选择当前最优解,而不考虑整体的最优解。
这种贪婪的选择策略通常是基于局部最优性的假设,即当前的选择对于后续步骤的选择没有影响。
贪心算法的优点是简单高效,但也存在一定的局限性。
二、实验案例:零钱兑换问题在本实验中,我们以零钱兑换问题为例,来说明贪心算法的应用。
问题描述:假设有不同面值的硬币,如1元、5元、10元、50元和100元,现在需要支付给客户x元,如何用最少的硬币数完成支付?解决思路:贪心算法可以通过每次选择当前面值最大的硬币来求解。
具体步骤如下:1. 初始化一个空的硬币集合,用于存放选出的硬币。
2. 从面值最大的硬币开始,如果当前硬币的面值小于等于待支付金额,则将该硬币放入集合中,并将待支付金额减去该硬币的面值。
3. 重复步骤2,直到待支付金额为0。
实验过程:以支付金额为36元为例,我们可以通过贪心算法求解最少硬币数。
首先,面值最大的硬币为100元,但36元不足以支付100元硬币,因此我们选择50元硬币。
此时,剩余待支付金额为36-50=-14元。
接下来,面值最大的硬币为50元,但待支付金额为负数,因此我们选择下一个面值最大的硬币,即10元硬币。
此时,剩余待支付金额为-14-10=-24元。
继续选择10元硬币,剩余待支付金额为-24-10=-34元。
再次选择10元硬币,剩余待支付金额为-34-10=-44元。
最后,选择5元硬币,剩余待支付金额为-44-5=-49元。
由于待支付金额已经为负数,我们无法继续选择硬币。
此时,集合中的硬币数为1个50元和3个10元,总共4个硬币。
实验结果:通过贪心算法,我们得到了36元支付所需的最少硬币数为4个。
贪心算法的基本原理
贪心算法的基本原理贪心算法(Greedy Algorithm)是一种常用的算法思想,它在求解最优化问题时通常能够得到较好的近似解。
贪心算法的基本原理是:每一步都选择当前状态下的最优解,从而希望最终能够得到全局最优解。
在实际应用中,贪心算法常常用于解决一些最优化问题,如最小生成树、最短路径、任务调度等。
一、贪心算法的特点贪心算法具有以下特点:1. 简单:贪心算法通常比较简单,易于实现和理解。
2. 高效:贪心算法的时间复杂度通常较低,能够在较短的时间内得到结果。
3. 局部最优:每一步都选择当前状态下的最优解,但不能保证最终能够得到全局最优解。
4. 适用范围:贪心算法适用于一些特定类型的问题,如无后效性、最优子结构等。
二、贪心算法的基本原理贪心算法的基本原理可以概括为以下几个步骤:1. 初始状态:确定问题的初始状态,定义问题的输入和输出。
2. 状态转移:根据当前状态,选择局部最优解,并更新状态。
3. 筛选解:判断当前状态下是否满足问题的约束条件,若满足则保留该解,否则舍弃。
4. 终止条件:重复以上步骤,直至满足终止条件,得到最终解。
三、贪心算法的应用举例1. 找零钱:假设有 25、10、5、1 四种面额的硬币,需要找零 41 元,如何使得找零的硬币数量最少?贪心算法可以先选择面额最大的硬币,然后逐步选择面额较小的硬币,直至找零完毕。
2. 区间调度:给定一组区间,如何选择最多的互不重叠的区间?贪心算法可以先按照区间的结束时间排序,然后依次选择结束时间最早的区间,直至所有区间都被覆盖。
3. 最小生成树:在一个连通的带权无向图中,如何选择边使得生成树的权值最小?贪心算法可以按照边的权值从小到大排序,然后依次选择权值最小且不构成环的边,直至所有顶点都被连接。
四、贪心算法的优缺点1. 优点:贪心算法简单高效,适用于一些特定类型的问题,能够在较短的时间内得到近似最优解。
2. 缺点:贪心算法不能保证一定能够得到全局最优解,可能会出现局部最优解不是全局最优解的情况。
贪心算法程序设计
贪心算法程序设计贪心算法程序设计1. 什么是贪心算法贪心算法(Greedy Algorithm)是一种常见的算法思想,它在每一步选择中都采取当前状态下的最优选择,从而希望最终达到全局最优解。
贪心算法的核心思想是局部最优解能导致全局最优解。
2. 贪心算法的基本步骤贪心算法的基本步骤如下:1. 定义问题的优化目标。
2. 将问题分解成子问题。
3. 选择当前最优的子问题解,将子问题的解合并成原问题的解。
4. 检查是否达到了问题的优化目标,如果没有达到,则回到第二步,继续寻找下一个最优子问题解。
5. 在所有子问题解合并成原问题解后,得到问题的最优解。
3. 贪心算法的应用场景贪心算法的应用非常广泛,几乎可以用于解决各种优化问题。
以下几个常见的应用场景:1. 零钱找零问题:给定一定面额的纸币和硬币,如何找零使得所需纸币和硬币的数量最小?2. 区间调度问题:给定一些活动的开始时间和结束时间,如何安排活动使得可以办理的活动数量最大?3. 背包问题:给定一些具有重量和价值的物品,如何选择物品使得背包的总价值最大?4. 最小树问题:给定一个带权无向图,如何找到一棵树,使得它的边权之和最小?5. 哈夫曼编码问题:给定一组字符和相应的频率,如何构造一个满足最低编码长度限制的二进制编码?4. 贪心算法的优缺点贪心算法的优点是简单、高效,可以快速得到一个近似最优解。
而且对于一些问题,贪心算法能够得到全局最优解。
贪心算法的缺点在于它不一定能够得到全局最优解,因为在每一步只考虑局部最优解,无法回溯到之前的选择。
5. 贪心算法的程序设计在使用贪心算法进行程序设计时,通常需要以下几个步骤:1. 定义问题的优化目标。
2. 将问题分解成子问题,并设计子问题的解决方案。
3. 设计贪心选择策略,选择局部最优解。
4. 设计贪心算法的递推或迭代公式。
5. 判断贪心算法是否能够得到全局最优解。
6. 编写程序实现贪心算法。
6.贪心算法是一种常见的算法思想,它在每一步选择中都采取当前状态下的最优选择,从而希望最终达到全局最优解。
如何证明贪心算法
这里主要是介绍一种证明贪心算法是最优的一种方法:Exchange Argument (不知道应该怎么翻译到中文,交换参数?感觉听起来挺别扭的,不像是一个方法的名字~o(╯□╰)o)Exchange Argument的主要的思想也就是先假设存在一个最优的算法和我们的贪心算法最接近,然后通过交换两个算法里的一个步骤(或元素),得到一个新的最优的算法,同时这个算法比前一个最优算法更接近于我们的贪心算法,从而得到矛盾,原命题成立。
下面来看一个更为formal的解释:步骤:Step0: 给出贪心算法A的描述Step1: 假设O是和A最相似(假设O和A的前k个步骤都相同,第k+1个开始不同,通常这个临界的元素最重要)的最优算法Step2: [Key] 修改算法O(用Exchange Argument,交换A和O中的一个元素),得到新的算法O’Step3: 证明O’ 是feasible的,也就是O’是对的Step4: 证明O’至少和O一样,即O’也是最优的Step5: 得到矛盾,因为O’ 比O 更和A 相似。
证毕。
当然上面的步骤还有一个变种,如下:Step0: 给出贪心算法A的描述Step1: 假设O是一个最优算法(随便选,arbitrary)Step2: 找出O和A中的一个不同。
(当然这里面的不同可以是一个元素在O不再A,或者是一个pair 的顺序在A的和在O的不一样。
这个要根据具体题目)Step3:Exchange这个不同的东西,然后argue现在得到的算法O' 不必O差。
Step4: Argue 这样的不同一共有Polynomial个,然后我exchange Polynomial次就可以消除所有的不同,同时保证了算法的质量不比O差。
这也就是说A 是as good as 一个O的。
因为O是arbitrary 选的,所以A是optimal的。
证毕下面给几个例子:例Maximum Cardinality Disjoint Interval Problem问题描述:给一些时间片段集合T={(a1,b1)(a2,b2),。
贪心算法的基本要素
贪心算法的基本要素贪心算法是一种非常简单但有效的算法设计策略,可用于解决一些最优化问题。
它通过找到每个阶段的局部最优解,并将其累积以得到全局最优解。
在实践中,贪心算法通常易于实现且效率较高。
下面将介绍贪心算法的基本要素。
1.最优子结构性质:贪心算法的最优子结构性质是贪心策略的基础。
它表示问题的最优解可以通过在每个阶段选择局部最优解来得到。
换句话说,问题的最优解包含了其子问题的最优解。
2.贪心选择性质:贪心算法的贪心选择性质是指在每个阶段选择局部最优解,以期望达到全局最优解。
这意味着贪心算法不会回退或改变之前所做的选择。
3.贪心算法的设计:贪心算法通常由以下步骤组成:(a)将问题分解为若干个子问题,并找到子问题的最优解;(b)找出每个子问题的局部最优解,并将其融合到全局最优解中;(c)使用贪心选择策略进行迭代,直到获得全局最优解。
4.贪心算法的正确性证明:在设计贪心算法时,需要证明贪心选择的局部最优解也是全局最优解。
这通常涉及数学归纳法、反证法或其他数学证明方法。
通过正确性证明,可以确保贪心算法能够正确地解决问题。
5.问题的适用性:贪心算法通常适用于满足最优子结构性质且贪心选择性质成立的问题。
但并非所有问题都适用于贪心算法。
在实践中,需要仔细分析问题的特点和要求,确定是否可以使用贪心算法求解问题。
1.零钱找零问题:给定一定面额的硬币,如何使用最少数量的硬币找零?贪心策略是在每个阶段选择面额最大的硬币,直到找零完毕。
2.活动选择问题:给定一组活动的开始时间和结束时间,如何安排最多的互不重叠活动?贪心策略是在每个阶段选择结束时间最早的活动,并删除与之冲突的活动。
3.部分背包问题:给定一组物品以及它们的重量和价值,如何选择物品以在限定重量内获得最大的总价值?贪心策略是计算每个物品的单位价值,并选择单位价值最高的物品放入背包中。
4.最小生成树问题:给定一个无向图,如何选择其中的边以连接所有顶点且总权重最小?贪心策略是在每个阶段选择权重最小的边,并保证该边不会形成环路。
贪 心 算 法
贪心算法及几个常用的例题贪心算法:一、基本概念:所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。
也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。
贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。
必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关。
所以对所采用的贪心策略一定要仔细分析其是否满足无后效性。
二、贪心算法的基本思路:1.建立数学模型来描述问题。
2.把求解的问题分成若干个子问题。
3.对每一子问题求解,得到子问题的局部最优解。
4.把子问题的解局部最优解合成原来解问题的一个解。
三、贪心算法适用的问题贪心策略适用的前提是:局部最优策略能导致产生全局最优解。
实际上,贪心算法适用的情况很少。
一般,对一个问题分析是否适用于贪心算法,可以先选择该问题下的几个实际数据进行分析,就可做出判断。
四、贪心算法的实现框架从问题的某一初始解出发;while (能朝给定总目标前进一步)利用可行的决策,求出可行解的一个解元素;由所有解元素组合成问题的一个可行解;五、贪心策略的选择因为用贪心算法只能通过解局部最优解的策略来达到全局最优解,因此,一定要注意判断问题是否适合采用贪心算法策略,找到的解是否一定是问题的最优解。
几个经典的例子:一、定义什么是贪心算法呢?所谓贪心算法是指,在对问题求解时,总是做出在当前看来最好的选择。
也就是说,不从整体最优解出发来考虑,它所做出的仅是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题都能产生整体最优解或整体最优解的近似解。
贪心算法的基本思路如下:1. .建立数学模型来描述问题。
2. 把求解的问题分成若干个子问题。
3. 对每个子问题求解,得到每个子问题的局部最优解。
4. 把每个子问题的局部最优解合成为原来问题的一个解。
关于拟阵以及贪心算法
关于拟阵以及贪⼼算法0. 核⼼思想拟阵问题的核⼼是找到具体问题中独⽴性的表现形式,然后找到⼀个能快速判断当前⼦集是否满⾜独⽴性的算法F,F的复杂度将会直接影响整个算法的复杂度1. 观前提⽰:每个⼈的思路不同,⾃然思考时遇到的困难那就不同,我这⾥仅仅是记录了⾃⼰思考过程中的困难以及理解思路,所以叙事的详略也只是根据我个⼈的思路⽽⾔,⾄于能否帮到读者就不好说了,当然我还是希望我的解释过程能对你的理解产⽣帮助。
⽂章内容部分来源⽹络,仅当作个⼈备忘。
2. 拟阵的定义及性质拟阵是⼀个满⾜如下条件的序偶 M = (S , I)1. S是⼀个有限集2. I 是S的⼦集的⼀个⾮空集族,这些⼦集称为S的独⽴⼦集,使得如果B∈I,且A包含于B,则A∈I,如果I满⾜此性质,则称之为遗传的。
空集必然是I的成员3. 如果A∈I,B∈I 且A⽐B元素数更少,那么存在某个元素x属于B-A使得A∪{x}∈I,则称拟阵M满⾜交换性质(关于第三条交换性的个⼈理解:拟阵具有膨胀性,总是可以膨胀(或者说,扩展)成为极⼤独⽴集,这能解释为什么给定⼀个拟阵,这个拟阵中的所有基,具有同样的⼤⼩)下⾯以图拟阵为例进⾏分析,⾸先给出图拟阵的概念3. 图拟阵⾸先给出图拟阵的定义图拟阵(记为M_G = S_G , I_G)定义在⼀个给定的⽆向图G = (V , E)上,满⾜下列条件1. S_G定义为 E,也就是G的边集2. A 是 E 的⼦集,则A ∈ I_G 当且仅当A是⽆圈的。
换⽽⾔之,A是独⽴的当且仅当G_A形成⼀个森林结合图拟阵说明拟阵的三条性质⾸先⾮空有限集,显然边集S_G满⾜条件其次遗传性,考虑B ∈ I,且A包含于B。
A,B根据定义,显然是森林,森林的⾃⼰也还是森林,所以A ∈ I 也成⽴,遗传性得证最后考虑交换性,我们按照性质构造两个森林,分别记作A和B,他们的顶点集相同,这⾥不妨假设B⽐A包含有更多的边,于是,计算他们连通块的个数,根据图论⾥的公式,连通块个数 = 点数 - 边数(可以⾃⼰画个图感受⼀下,三个点,⼀条边,两个分量),于是B由于边更多,所以连通块数量就更少,整体上感受就是B是整块的,⽽A更加零碎更进⼀步,⼀定会有 B 中的⼀条边 e 连接 A 中的两个分量。
贪心算法的原理是
贪心算法的原理是
贪心算法是一种求解最优问题的常用算法思想,其基本原理是在每一步选择中都采取当前状态下最优的选择,从而希望最终得到全局最优解。
贪心算法的主要特点是局部最优策略同时也是全局最优策略。
贪心算法通常包含以下步骤:
1. 确定问题的最优子结构:即问题的整体最优解可以通过一系列局部最优解来达到。
这是贪心算法的基础,也是保证贪心选择性质的关键。
2. 构造贪心选择:通过局部最优策略来构造每一步的最优解,不考虑前面步骤的选择是否能够达到全局最优。
3. 解决子问题:将子问题缩小,通过递归或迭代的方式求解。
4. 合并子问题的解:将子问题的解合并起来,形成原问题的解。
贪心算法的正确性依赖于贪心选择性质和最优子结构性质。
贪心选择性质指的是,通过局部最优解就可以推导出全局最优解。
最优子结构性质指的是,问题的整体最优解可以通过一系列局部最优解来达到。
贪心算法的应用广泛,常见的问题包括:
1. 找零钱问题:给定一些面额不同的硬币和一个总金额,如何用最少数量的硬币凑出总金额。
2. 区间调度问题:给定一些活动的开始时间和结束时间,如何安排活动使得参加的活动数量最多。
3. Huffman编码问题:如何用最短的编码长度来表示一个给定概率分布的字符集。
虽然贪心算法通常能够在很短的时间内找到一个解,但并不是所有问题都适合使用贪心算法。
贪心算法不能保证得到最优解,只能保证得到一个近似最优解。
因此,在使用贪心算法解决问题时需要根据具体问题的特性来判断是否适合使用贪心算法。
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)。
贪心算法概述及研讨
对贪心算法的概述和研讨福州第一中学高一(8)班汪涛指导老师:陈颖算法总览当一个问题具有“最优子结构”时,我们可以采用动态规划法解决该问题。
但是有的时候,贪心算法可以更好的处理该类问题。
总体上看,贪心算法是一种高效的、不稳定的算法;但是它在解决问题时有很多独特的优良性质,掌握贪心算法有时可以非常迅速的获得最优解或近似最优解。
关键字:贪心算法(贪婪算法),贪心算法的应用举例,Object Pascal,快速算法,不稳定算法,信息学奥赛。
何时采用何时能,又何时应该采用贪心算法呢?一般认为,凡是经过数学归纳法证明可以采用贪心算法的情况,都应该采用它。
因为它的效率是很高的。
贪心算法的弱点在于它的不稳定性,即有时它不总能返回最优解。
那么能采用贪心算法的问题具有怎样的性质呢?(何时采用贪心算法)1、它具有和动态规划问题相似的性质,即分治法中的“最优子结构”性质,即每个子问题的最优解的集合就是整体最优解。
这是必须的性质,因为贪心算法解决的问题流程就需要依序研究每个子问题,然后综合之得出最后结果。
不能采用分治法解决的问题,是理论上是不能使用贪心算法的。
而且,必须拥有最优子结构性质,才能保证贪心算法返回最优解。
2、它必须具有一种特殊的“贪心选择性”。
这种性质类同于“最优子结构”性质,但又有一些小的差别。
我们知道,在动态规划中,每一个父问题结果的得出需要它的子问题作为条件;但是“贪心选择性”则不需要;贪心选择性所做的是一个非线性的子问题处理过程,即一个子问题并不依赖于另一个子问题,但是子问题间有严格的顺序性。
要证明一个问题具有“贪心选择性”,就必须证明每一步所做的贪心选择最终导致一个问题的整体最优解。
这也是必须的性质。
如果一个问题具有上述两个性质,理论上就应该采用贪心算法。
处理流程经由贪心算法处理的问题需要经过排序。
即把“最贪心”的子结果排在序列的最前面,一直到“最不贪心的”。
这是处理问题的第一步。
然后依序解决问题而得出最终结果。
部分背包问题的贪心算法正确性证明
部分背包问题的贪⼼算法正确性证明⼀,部分背包问题介绍⾸先介绍下0-1背包问题。
假设⼀共有N件物品,第 i 件物品的价值为 V i,重量为W i,⼀个⼩偷有⼀个最多只能装下重量为W的背包,他希望带⾛的物品越有价值越好,请问:他应该选择哪些物品?0-1背包问题的特点是:对于某件(更适合的说法是:某类)物品,要么被带⾛(选择了它),要么不被带⾛(没有选择它),不存在只带⾛⼀部分的情况。
⽽部分背包问题则是:可以带⾛⼀部分。
即,部分背包问题可带⾛的物品是可以⽆限细分的。
(连续与离散的区别)可以把0-1背包问题中的物品想象的⼀个⾦⼦,你要么把它带⾛,要么不带⾛它;⽽部分背包问题中的物品则是⼀堆⾦粉末,可以取任意部分的⾦粉末⼆,部分背包问题的贪⼼算法部分背包问题可以⽤贪⼼算法求解,且能够得到最优解。
贪⼼策略是什么呢?将物品按单位重量所具有的价值排序。
总是优先选择单位重量下价值最⼤的物品。
单位重量所具有的价值:V i / W i举个例⼦:假设背包可容纳50Kg的重量,物品信息如下:物品 i 重量(Kg) 价值单位重量的价值1 10 60 62 20 100 53 30 120 4按照我们的贪⼼策略,单位重量的价值排序:物品1 > 物品2 > 物品3因此,我们尽可能地多拿物品1,直到将物品1拿完之后,才去拿物品2.....最终贪⼼选择的结果是这样的:物品1全部拿完,物品2也全部拿完,物品3拿⾛10Kg(只拿⾛了物品3的⼀部分)这种选择获得的价值是最⼤的。
在(三)会给出证明。
⽽对于0-1背包问题,如果也按“优先选择单位重量下价值最⼤的物品”这个贪⼼策略,那么,在拿了物品1和物品2之后,就不能在拿物品3了。
因为,在拿了物品1和物品2之后,背包中已经装了10+20=30Kg的物品了,已经装不下物品3了(50-30 < 30)(0-1背包:⼀件物品要么拿,要么不拿,否能只拿⼀部分),此时得到的总价值是 160。
贪心算法
6.贪心方法模型
a.工程计划模型 b.部分背包与每步最优 c.构造贪心算法
a.工程计划模型
我们常常碰到这样的问题:完成一个工程需
要若干个步骤,每个步骤都有若干种方法, 图示—— 步骤a 步骤b 步骤c ... 步骤n 方法b1 方法c1 方法a1 方法b2 方法c2 方法n1 方法a2 方法b3 方法c3 方法c4
种树问题:一条街道分为n个区域(按1-n编号), 每个都可种一棵树。有m户居民,每户会要求在区 域i-j区间内种至少一棵树。现求一个能满足所有要 求且种树最少的方案。 算法构造: 1.对于要求,以区间右端(升序)为首要关键字, 左端(升序)为次要关键字排序。 2.按排好的序依次考察这些要求,若未满足,则在 其最右端的区域种树,这时可能会满足多个要求。 证明思路:解法并不唯一,关键是证明没有比该解 法更好的解法。按步骤1排序之后,会发现对于每 个要求,在最右边的区域内种树所得的结果总不会 差于在其他区域种树。至于为什么这样排序,留给 你——读者们思考吧。
每个方法有一个权值(如效率、质量),其大小往 往和其他步骤中选取的方法有关。有些时候权值无 意义,表示方法不可选择。要求给出一个方法组合, 是权值和最大。 在这里,暂且把它称作“工程计划”。很多实际问 题都可以归纳为这个模型。 对于不同形式的工程计划,我们有不同的解法。 若权值与整个过程或前后步骤的方法选择都有关, 我们使用搜索算法——时间复杂度高得吓人。 若每个权值只与上(或下)一步或少数几步的方法 选择都有关,我们使用动态规划——有比较高的效 率,在下一章会讲到。 若每个权值与其他步骤的方法选择都没有关系,我 们使用贪心方法。
算法分析:设a[i]为第I堆纸牌的张数(0<=I<=n), v为均分后每堆纸牌的张数,s为最小移动次数。 我们用贪心算法,按照从左到右的顺序移动纸牌。 如第I堆的纸牌数不等于平均值,则移动一次(即s 加1),分两种情况移动: 1.若a[i]>v,则将a[i]-v张从第I堆移动到第I+1堆; 2.若a[i]<v,则将v-a[i]张从第I+1堆移动到第I堆。 为了设计的方便,我们把这两种情况统一看作是将 a[i]-v从第I堆移动到第I+1堆,移动后有a[i]=v; a[I+1]=a[I+1]+a[i]-v. 在从第I+1堆取出纸牌补充第I堆的过程中可能回出 现第I+1堆的纸牌小于零的情况。
贪心算法-例题讲解
贪⼼算法-例题讲解前⾔:此博客在写作过程中参考了⼤量资料和博客,不能⼀⼀列举,还请见谅。
概述贪⼼法:从问题的某⼀个初始状态出发,逐步构造最优解从⽽向⽬标前进,并期望通过这种⽅法产⽣出⼀个全局最优解的⽅法贪⼼是⼀种解题策略,也是⼀种解题思想,⽽不是算法贪⼼策略与其他算法的区别贪⼼与递推:贪⼼法推进每⼀步不依据某⼀固定的递推式,⽽是当前看似最佳的贪⼼决策,不断的将问题归纳为更加⼩的相似的⼦问题贪⼼与动态规划:贪⼼是“⿏⽬⼨光”;动态规划是“统揽全局”贪⼼法的优缺点优点:思维复杂度低、代码量⼩、运⾏效率⾼、空间复杂度低等缺点:很难找到⼀个简单可⾏并且保证正确的贪⼼思路贪⼼算法的应⽤贪⼼算法的常⽤范围有明显的贪⼼可证明贪⼼策略的贪⼼(最常见的)贪⼼数据结构:堆/Kruskal/Prim/Dijkstra博弈/游戏策略,这些策略⼤多是贪⼼求较优解或多次逼近求最优解⼏个简单的贪⼼例⼦最优装载问题:给n个物体,第i个物体重量为wi,选择尽量多的物体,使得总重量不超过C贪⼼策略:先拿轻的部分背包问题:有n个物体,第i个物体的重量为wi,价值为vi,在总重量不超过C的情况下让总价值尽量⾼。
每⼀个物体可以只取⾛⼀部分,价值和重量按⽐例计算贪⼼策略:先拿性价⽐⾼的乘船问题:有n个⼈,第i个⼈重量为wi。
每艘船的载重量均为C,最多乘两个⼈。
⽤最少的船装载所有⼈贪⼼策略:最轻的⼈和最重的⼈配对例题(基础)1.删数问题-【问题描述】键盘输⼊⼀个⾼精度的正整数n(n<=240位),去掉其中任意s个数字后剩下的数字按照原来的次序将组成⼀个新的正整数。
编程对给定的n和s,寻求⼀种⽅案,使得剩下组成的新数最⼩。
贪⼼策略为:每⼀步总是选择⼀个使剩下的数最⼩的数字删去,即按⾼位到低位的顺序搜索,若各位数字递增,则删除最后⼀个数字,否则删除第⼀个递减区间的⾸字符。
然后回到串⾸,按上述规则再删除下⼀个数字。
重复以上过程s次,剩下的数字串便是问题的解了。
贪心算法的实验原理
贪心算法的实验原理贪心算法是一种基于贪心策略的算法,它在每个步骤中选择局部最优解,最终希望得到全局最优解。
因为贪心算法只关注当前局部最优解,而不考虑未来可能发生的变化,因此不一定能够得到全局最优解。
贪心算法的实验原理是通过对每个部分的最优或局部最优解做出选择,最终以得到全局最优解为目的进行优化的算法。
它在每个步骤中都尽可能地选取当前最优的选择,希望通过每一步的最优选择,实现最终结果的最优化。
在实现贪心算法时,需要明确贪心策略以及贪心策略的正确性,以保证算法能够得出正确的结果。
贪心算法的正确性可以通过以下几个方面来分析:1. 子问题的最优解能够推出原问题的最优解。
这意味着每个子问题都是局部最优解,并且子问题之间相互独立,不会互相影响。
2. 贪心策略能够保证每个步骤选取的局部最优解是全局最优解的一部分。
具体来说,每个步骤的最优解都应该满足贪心选择性质和最优子结构性质。
3. 贪心算法的选择性质和最优子结构性质都可以通过归纳法来证明。
对于选择性质,假设最终结果不是局部最优解的组合,而是由不同的选择组成的组合。
我们可以证明,将任意一个非局部最优选择替换为其局部最优选择,最终结果仍然是全局最优解。
对于最优子结构性质,假设设子问题的最优解可以推导出原问题的最优解。
我们可以证明,当我们将一个子问题的最优解与另一个子问题的最优解组合在一起时,可以得到原问题的最优解。
贪心算法与动态规划算法都可以用于求解优化问题。
与动态规划算法相比,贪心算法常常更快、更简单,但其结果有时并不一定是最优的。
对于某些优化问题,贪心算法可以得到与动态规划算法相近甚至相等的结果,但对于某些问题,贪心算法则难以得到全局最优解。
算法设计与分析论文(贪心算法)
贪心选择是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪 心选择来达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划 算法的主要区别。
贪心选择是采用从顶向下、以迭代的方法做出相继选择,每做一次贪心选择 就将所求问题简化为一个规模更小的子问题。对于一个具体问题,要确定它是否 具有贪心选择的性质,我们必须证明每一步所作的贪心选择最终能得到问题的最 优解。通常可以首先证明问题的一个整体最优解,是从贪心选择开始的,而且作 了贪心选择后,原问题简化为一个规模更小的类似子问题。然后,用数学归纳法 证明,通过每一步贪心选择,最终可得到问题的一个整体最优解。
物品超出背包容量为止。伪代码如下:
public static void DepWePr(double[][] a, double c, int[] ans) { // depend on
// the // weight // and price double[] w = new double[a[0].length]; // the weight of goods System.arraycopy(a[0], 0, w, 0, w.length); // copy the array
贪心算法
——不在贪心中爆发,就在贪心中灭亡 徐晓龙 武汉理工大学计算机科学与技术学院软件 ZY1101 班
摘要
本文介绍贪心算法的基本意义以及算法的使用范围,并通过具体的案例来分 析贪心算法的具体应用,从而指出其特点和存在问题。 关键字:贪心算法,贪心策略,TSP、0/1 背包
引言
我们用了 13 周的时间学完了《算法设计与分析》这本书。这本书中涵盖了 大量的常见算法,包括蛮力法、分治法、动态规划法、贪心算法等等。我最有印 象的就是贪心算法。贪心算法是一种有合理的数据组织和清晰高效的算法,它简 单有效。下面我们来详细解读一下这个算法。
贪心算法
max vi xi
i 1
n
于是,背包问题归结为寻找一个满足约束条 件式,并使目标函数式达到最大的解向量X=(x1, x2, …, xn)。
至少有三种看似合理的贪心策略: (1)选择价值最大的物品,因为这可以尽可能快 地增加背包的总价值。但是,虽然每一步选择获得 了背包价值的极大增长,但背包容量却可能消耗得 太快,使得装入背包的物品个数减少,从而不能保 证目标函数达到最大。 (2)选择重量最轻的物品,因为这可以装入尽可 能多的物品,从而增加背包的总价值。但是,虽然 每一步选择使背包的容量消耗得慢了,但背包的价 值却没能保证迅速增长,从而不能保证目标函数达 到最大。 (3)选择单位重量价值最大的物品,在背包价值 增长和背包容量消耗两者之间寻找平衡。
算法
main( ) { int i,j,n,GZ,A; int B[8]={0,100,50,20,10,5,2,1},S[8]; input(n); for(i=1;i<=n;i++) { input(GZ); for(j=1,j<=7;j++) { A=GZ/B[j]; S[j]=S[j]+A; GZ=GZ-A*B[j];} } for(i=1;i<=7;i++) print(B[i], “----”, S[i]); }
∞ b 4 0 a 8 h ∞ 4 b 4 0 a 8 h 8 11 7 11 7
8 ∞ i 6 1 2
∞ c
7
∞ d 14 9 e ∞ 10
4 g ∞
2
f ∞
(a)
8 ∞ i 6 1 g ∞ 2 4 f ∞ ∞ c 7 ∞ d 14 9 e ∞ 10 2
贪心法求解活动安排问题的关键是如何选择贪心策略,使 得按照一定的顺序选择相容活动,并能安排尽量多的活动。至 少有两种看似合理的贪心策略: (1)最早开始时间:这样可以增大资源的利用率。 (2)最早结束时间:这样可以使下一个活动尽早开始。
贪心算法的基本框架
贪心算法是一种常用的优化算法,它通过在每一步选择当前状态下的最优解来逐步求解问题。
下面是贪心算法的基本框架:
1.确定问题的最优子结构:
•首先,要确保问题具有最优子结构属性,即问题的最优解可以由子问题的最优解构成。
2.定义贪心策略:
•根据问题的特性,确定贪心策略,即在每一步选择中采取的决策规则。
贪心策略应该是局部最优的,并且希望通过局部最优解来达到
全局最优解。
3.构建解决方案:
•通过贪心策略,在每一步选择中确定当前的最优解。
•逐步构建解决方案,直到得到最终的全局最优解。
4.证明贪心选择的正确性:
•为了保证贪心算法的正确性,需要进行正确性证明。
证明贪心选择的每一步都不会破坏最优解的性质,从而保证最终得到的解是全局
最优解。
需要注意的是,贪心算法并不适用于所有问题,因为贪心策略可能会导致得到次优解或根本无法得到最优解。
在使用贪心算法时,需要仔细分析问题的特性,确保问题满足贪心算法的要求,并进行正确性分析。
总之,贪心算法的基本思想是通过每一步的局部最优选择来达到全局最优解。
在实际应用中,可以根据具体问题的特点设计相应的贪心策略。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
这里主要是介绍一种证明贪心算法是最优的一种方法:Exchange Argument (不知道应该怎么翻译到中文,交换参数?感觉听起来挺别扭的,不像是一个方法的名字~o(╯□╰)o)
Exchange Argument的主要的思想也就是先假设存在一个最优的算法和我们的贪心算法最接近,然后通过交换两个算法里的一个步骤(或元素),得到一个新的最优的算法,同时这个算法比前一个最优算法更接近于我们的贪心算法,从而得到矛盾,原命题成立。
下面来看一个更为formal的解释:
步骤:
Step0: 给出贪心算法A的描述
Step1: 假设O是和A最相似(假设O和A的前k个步骤都相同,第k+1个开始不同,通常这个临界的元素最重要)的最优算法
Step2: [Key] 修改算法O(用Exchange Argument,交换A和O中的一个元素),得到新的算法O’Step3: 证明O’ 是feasible的,也就是O’是对的
Step4: 证明O’至少和O一样,即O’也是最优的
Step5: 得到矛盾,因为O’ 比O 更和A 相似。
证毕。
当然上面的步骤还有一个变种,如下:
Step0: 给出贪心算法A的描述
Step1: 假设O是一个最优算法(随便选,arbitrary)
Step2: 找出O和A中的一个不同。
(当然这里面的不同可以是一个元素在O不再A,或者是一个pair 的顺序在A的和在O的不一样。
这个要根据具体题目)
Step3:Exchange这个不同的东西,然后argue现在得到的算法O' 不必O差。
Step4: Argue 这样的不同一共有Polynomial个,然后我exchange Polynomial次就可以消除所有的不同,同时保证了算法的质量不比O差。
这也就是说A 是as good as 一个O的。
因为O是arbitrary 选的,所以A是optimal的。
证毕
下面给几个例子:
例Maximum Cardinality Disjoint Interval Problem
问题描述:给一些时间片段集合T={(a1,b1)(a2,b2),。
,(an,bn)},找出一个元素个数最多的子集S,子集中的每个元素的时间片段没有交叉。
Greedy Algorithm: 每次都选所有interval 中bi最小的那个,把(ai,bi)加入S,然后把(ai,bi)在T中删除,同时把T中所有和(ai,bi)有交叉的interval删除,然后再在T中找最小的bj,循环上面的操作,直到没有可以在添加的。
证明上面说的Greedy Algorithm是最优的。
下面就用第一个证明的步骤来证。
我们的Greedy Algorithm记为A,假设A不是最优的,那么就一定存在一个O,O是和A最相近的一个最优的算法,最相近是指和O和A的前K-1个选择都相同,第K个是不同的。
假设对于A,A第k个选择的是(ai,bi);而O第K个选择的是(aj,bj)。
从A的定义我们可以直到,bi<=bj。
现在我们构造一个O',O' = O-(aj,bj)+(ai,bi)。
1)很显然,O'是这个问题的一个解,也就是说O'中的intervals没有重叠的。
在O'中,(ai,bi)前的intervals和A中的一样,所以前一部分没有重叠。
在(ai,bi)后的intervals 和O中的一样,所以也没有重叠,同时bi<=bj,所以(ai,bi)也不会和它相邻的重叠,所以O'中的所有intervals都没有重叠。
2)O'是一个最优解,因为他的intervals的个数和O一样。
综上,我们找到了一个最优解O',它和A具有的共同的intervals有K个,这和我们前提假设最多有k-1个相矛盾,所以,A是最优的。
证毕。
例Scheduling with Deadline
问题描述:有一系列的tasks{a1,a2,。
,an},每个task需要在cpu上跑{p1,p2,。
,pn}个units的时间,cpu是非抢占式的,也就是task一旦获得cpu,就运行直到他完成,{c1,c2,。
,cn}是每个task的完成时间,我们现在要minimize的就是(c1+c2+。
+cn)/n。
所有的task一起release。
Greedy Algorithm:每次选运行时间最小的那个task运行。
证明上面说的Greedy Algorithm是最优的。
同样还是用第一个证明的步骤来证。
假设A不是最优的,那么一定存在一个最优的O,和A最接近,他们选择的前k-1个task是相同的。
如下:
No.123。
k。
A 。
ai。
aj 。
O 。
aj。
ai 。
根据A的定义,我们知道,pi <= pj的。
现在我们就来构造O',当然,O'就是把O中的ai和aj两个元素交换一下,即
No.123。
k。
t。
A 。
ai。
aj 。
O 。
aj。
ai 。
O' 。
ai。
aj 。
对于整个的完成时间,我们可以给出计算公式的,假设b1,b2,。
,bn是一个调度序列(bi是task 的index,也就是{bi}是所有task的index的一个permutation),即task执行顺序是
a_{bi},a_{b2}, ..., a_{bn}。
举个例子如果只有5个task,a1,a2,a3,a4,a5。
{bi} = {2,1, 3, 5, 4},那也就是task的执行序列为a2,a1,a3,a5,a4。
(博客里面不能打数学公式就是不爽啊~)
还是用上面的5个例子算了,对于a2,a1,a3,a5,a4,我们知道总时间其实是5个a2的时间,即p2,4个a1的时间,即p1,依次类推,所以总时间是5*p2+4*p1+3*p3+2*p5+p4。
好,有了上面的计算总时间的概念,下面就来分别计算一下O和O'的总时间,其实我们需要比较它们谁大谁小,通常只要比较一下他们的差就行了,即Time(O)-Time(O')。
同时很显然,他们的差只是由aj和ai引起的,其他的并没有改变。
我们知道在O中,aj是第k个选的,ai是第t个选的,而在O'中,ai是第k个选的,aj是第t个选的,所以Time(O)-Time(O') = (n-k+1)*pj + (n-t+1)*pi - (n-k+1)*pi - (n-t+1)*pj = k*(pj-pi) - t*(pj-pi) = (pi-pj)*(k-t)>=0,即我们得到Time(O) >= Time(O'),这也就是说我们找到了一个O',他是最优的,同时O'和A有K个common element,所以得出矛盾。
证毕。
例Kruskal Algorithm for Minimum Spanning Tree(最小生成树)
问题描述:对于边集合E,先按每个边的cost排序,从小到大,然后按如下方法构造一个MST,每次选cost最小的那个边,添加进我们的MST,如果一个边使我们现有的MST出现环路,则把这条边舍弃,然后重复上面的操作。
(感觉现在表达越来越搓了,没看明白怎么回事的童鞋看这里
吧 /wiki/Kruskal's_algorithm)
下面我们就用第二种证明方法来证明Kruskal Algorithm算法是最优的。
假设我们的graph是G(V,E),有一个optimal的算法O,它生成的MST是T1,Kruskal生成的树是
T2,这样,因为T2!=T1(如果相等我们的Kruskal就最优了,就不用证了),所以至少有一条边e,e 在T1中,同时e不在T2中。
这个与众不同的e就是我们的切入点。
可以想象,如果我们把e在T1中去掉,T1就变成了两部分,即Ta和Tb,我们知道{Ta中的点}V{Tb中的点} = V(就是Ta中的点并上Tb中的点就是我们G中的点集V),所以在T2中,一定有一条边f(f!=e),f的一个点在{Ta中的点},f的另一个点在{Tb中的点}。
根据我们的Greedy算法Kruskal,我们没有选e,是因为e在我们的图中造成了回路。
在进一步想,有回路是因为我们先选了f,这就说明cost(f) <= cost(e)。
(恩,这就是我们的重点啊,笑一个O(∩_∩)O~)
下面的也就很显然了,我们考虑构造一棵新的树,T3,对于T3 = E(T1) - e + f,也就是T3中的边是
T1中的所有边除了e,同时加上边f。
1)很显然,我们知道T3是一棵spanning tree,f连通了由去掉e而分隔的两部分。
2)很显然,T3的cost是<= T1的cost的。
因为cost(f) <= cost(e),且其他不变。
即T3是MST。
所以同个上面的构造,我们就构造出了一棵树,这个树是MST,同时它比T1更接近于T2。
(多了一条common的边)
我们知道T1和T2对多有n条边是不同的,通过上面的步骤,我们可以经过n次变换,得到T2,同时cost <=T1,所以,T2是MST。
证毕。