java u003_003-贪心算法

本文介绍了贪心算法的概念、基本思想和性质,并通过活动选择问题、最优装载问题和最小延迟调度问题三个经典案例,详细阐述了贪心算法的解决策略和正确性证明。贪心算法具有简单和低复杂性的优势,但在设计时需注重正确性证明。
摘要由CSDN通过智能技术生成

263b233606150c3728c82f8a9f047369.png

贪心算法

算法概述

贪心算法也叫贪婪算法,是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优解出发来考虑,它所做出的仅是在某种意义上的局部最优解。(所谓贪心即只看眼前不管未来)

【注意:】

贪心方法是一种分级处理方法,首先要根据题意,选取一种量度标准(贪心策略),然后根据量度标准对成本进行排序,再根据题目的约束条件进行选择。对于一个问题可能会有不同的量度标准,选择其中可以获得最优解的量度标准(贪心策略)是贪心法设计的核心问题

贪心算法的基本思想

建立数学模型来描述问题。

把求解的问题分成若干个子问题。

对每一子问题求解,得到子问题的局部最优解。

把子问题的解局部最优解合成原来解问题的一个解。

【注意:贪心法要进行正确性证明,证明其不正确举反例即可】

贪心法的正确性证明

【个人感觉应该是贪心法的难点之处】

贪心法正确性证明常用的方法有归纳法(对算法步数归纳、对问题归纳)和交换论证法(从最优解出发,不变坏地替换,得到贪心策略的解)。下面的例子介绍时会详细介绍

活动选择问题——对算法步数归纳

最优装载问题——对问题规模归纳

最小延迟调度——交换论证

贪心算法的性质

贪心选择可以依赖以往所做过的选择,但绝不依赖于将来所作的选择,也不依赖于子问题的解。(区别于动态规划)

贪心算法通常以自顶向下的方式进行,不断迭代做出贪心选择,每做一次贪心选择就将问题简化为规模更小的问题。

【你会发现贪心法其实和动态规划有点相似之处,但也有很大区别】

贪心法的优势

算法简单,时间和空间复杂性低

>

>

>

>

话不多说直接上栗子,一目了然

经典例子

活动选择问题

最优装载问题

最小延迟调度问题

一一活动选择问题

●问题介绍

S = {1, 2, … , n}为n 项活动的集合, si , fi 分别为活动 i 的开始和结束时间. 活动i与j相容即si ≥fj 或 sj ≥fi .求最大的相容活动集

●贪心策略

策略1:开始时间早的优先排序使 s1≤s2≤…≤sn,从前向后挑选

不正确(反例):

反例:S={1,2,3 }s1=0,f1=20,s2=2,f2=5,s3=8,f3=15

解(活动1)

5ddd5235c38a344ec0aecffff222acf3.png

策略2:占用时间少的优先排序使得 f1-s1≤ f2-s2≤…≤fn-sn,从前向后挑选

不正确(反例)

反例:S = { 1, 2, 3 }s1=0, f1=8, s2=7, f2=9, s3=8, f3=15

解(活动2)

079b3a29fcbb3675f0e436a2b0d620fd.png

策略3:结束早的优先排序使 f1≤f2≤…≤ fn,从前向后挑选

解(活动1、3)

●伪码:

2e962c8ebe90b3b1f4cd8e26f07e0cc4.png

●正确性证明(对算法步数归纳)

命题:算法Select执行到第k步,选择k项活动i1=1,i2,…,ik,那么存在最优解 A包含活动 i1=1, i2 ,…, ik .

只要此定理成立,算法至多到第n步得到最优解

归纳证明

设S={1,2,….n}为活动集且f1≤…≤ fn

归纳基础: k=1, 证明存在最优解包含活动 1 ,k=1, 证明存在最优解包含活动1

证:任取最优解A, A中活动按截止时间递增排列. 如果A的第一个活动为 j,j ≠1, 用1替换A的活动 j 得到解 A',即A' = (A−{ j }) ∪{1}, 由于 f1 ≤ fj , A' 也是最优解,且含有1.

归纳步骤:

假设命题对k为真, 证明对k+1也为真.

证:算法执行到第 k 步, 选择了活动i1=1,i2, …, ik , 根据归纳假设存在最优解 A包 含i1=1,i2,…,ik , A中剩下活动选自集合S'

S' = { i | i∈S, si ≥ fk }

A = { i1, i2, … , ik } ∪ B

437842adc7239eb076aefee7c901a725.png

证:B是 S'的最优解.(若不然, S' 的最优解为B*, B*的活动比 B多,那么B*∪{1, i2, … , ik } 是 S 的最优解,且比 A的活动多,与 A 的最优性矛盾.)

9848b84633a0c7fbb17314903c7fd9dc.png

证:将S' 看成子问题,根据归纳基础,存在 S' 的最优解B' 有S' 中的第一个活动 ik+1, 且 |B' | = |B|, 于是

{ i1, i2, ... , ik } ∪ B'= { i1, i2, ... , ik , ik+1 } ∪ ( B'−{ ik+1})也是原问题的最优解

c16a98f5579d754278de0b490c3ba955.png

●程序:

5258c0f654e5a3d9bbede908d7dc8fba.png

●时间复杂度

O(n) =O(n)(输入时已排好序)

一一最优装载问题

●问题介绍

n 个集装箱1, 2, … , n 要装上轮船,集装箱 i 的重量为 wi , 轮船装载重量限制为C, 无体积限制. 问如何装使得上船的集装箱最多?假设每个箱子的重量 wi≤C.

【类似于0-1背包问题】

●建模

设 表示解向量,xi = 0,1(0代表不装,1代表装)xi = 1表示当且仅当第 i 个集装箱被装上船

5215ad0ba7ec41797dec99dcc0e58e1f.png

●算法策略

将集装箱按照重量递增顺序进行排列,轻者优先

●正确性证明(对问题规模归纳)

设集装箱从轻到重记为1, 2, … , n.

命题:对装载问题任何规模为 n 的输入实例,算法得到最优解.

归纳基础:

证:对任何只含 1个箱子的输入实例,贪心法得到最优解. 显然正确.

归纳步骤:

假设对于任何n个箱子的输入实例贪心法都能得到最优解,那么对于任何n+1个箱子的输入实例贪心法也得到最优解.

归纳步骤证明思路

d81396076a1c6a3f3732222c94e8e101.png

假设对于 n 个集装箱的输入,贪心法都可以得到最优解,考虑 输入N = { 1, 2, … , n+1 } 其中 w1 ≤ w2 ≤ … ≤ wn+1.

证:由归纳假设,对于N' = {2,3, …, n+1},C' = C− w1,贪心法得到最优解 I'.

令I = I '∪{1}

证:I (算法解)是关于 N 的最优解. 若不然,存在包含 1 的关于 N 的最优解 I*(如果 I* 中没有1,用 1 替换 I* 中的第一个元素得到的解也是最优解), 且 |I*|>| I |;那么I*−{1}是 N' 和C' 的解且| I*− {1}| > | I − {1} | = | I' | 与 I'是关于N' 和C' 的最优解矛盾.

d8051ca4af0605bea28200cdd65a184b.png

一一最小延迟调度问题

●问题介绍

客户集合A,∀i∈A,ti 为服务时间,di 为要求完成时间,ti, di为正整数. 一个调度f : A→N,f(i)为客户 i 的开始时间. 求最大延迟达到最小的调度,即求 f 使得

f0ffd5f36251246a3e55aa95afab911d.png

●贪心策略

按照 di 从小到大安排,即按完成时间从早到晚安排任务,没有空闲.

●伪码

f75f36d833d1cc3134f584677c51d980.png

●正确性证明(交换论证)

没有空闲时间, 没有逆序. 逆序 ( i, j ): f (i) < f (j) 且 di > dj (逆序即i比j结束时间晚却先执行了)

命题:所有没有逆序、没有空闲时间的调度具有相同的最大延迟

证:设 f 没有逆序,在 f 中具有相同完成时间 d 的客户i1, i2, … , ik连续安排, 其开始时刻为 t0, 完成这些任务的时刻是 t,最大延迟为最后任务延迟t−d, 与 i1, i2, … , ik的排列次序无关.t = t0+ (ti1+ ti2+ ...+ tik)

bfba3dcbf2cf92081883af6c37b6c582.png

证明思想:从一个没有空闲时间的最优解出发,在不改变最优性的条件下,转变为没有逆序的解。

如果一个最优调度存在逆序,那么存在i < n使得(i,i+1构成一个逆序)

存在逆序(i,j),j = i + 1,那么交换i和j得到的解的逆序数减一,后面证明这个新的调度仍然最优

至多经过n(n-1)/2次交换得到一个没有逆序的最优调度

证:交换相邻逆序仍旧最优

设 f1是一个任意最优解,存在相邻逆序( i, j ) . 交换 i 和 j 的顺序, 得到解 f2. 那么f2的最大延迟不超过 f1的最大延迟.

交换 i, j 与其他客户延迟时间无关

交换后不增加 j 的延迟,但可能增加 i的延迟

i 在 f2的延迟小于 j 在 f1 的延迟 ,因此小于f 1的最大延迟 r

6d50fc9184112ee4fb5e3eeba01caf77.png

●程序:

25d073660a423b13d676a74595beebd4.png

●时间复杂度为

O(nlogn) +O(n) =O(nlogn)

【可以看出贪心法的程序设计和思路其实很简单,个人感觉难点就在于证明贪心策略的正确性,如果一个问题可以用贪心法解决的话,首选贪心法】

Thank    u

--End--

谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值