【算法】贪心算法(第四章习题解答)

文章讨论了贪心算法在特殊0-1背包问题中的有效性,证明了在物品重量递增、价值递减的情况下,贪心算法能得出最优解。同时指出贪心算法不能保证解决两艘船的最优装载问题,并给出了反例。另外,文章还证明了关于字符集合的任何最优前缀码可以表示特定长度的编码序列。最后,提出了一种算法来确定最少删除多少闭区间以使剩余区间不相交,该算法基于区间右端点排序。
摘要由CSDN通过智能技术生成

4 贪心算法

在这里插入图片描述

4.1

若在 0 − 1 0-1 01 背包问题中, 各物品依重量递增排列时, 其价值恰好依递减序排列. 对于这个特殊的 0 − 1 0-1 01 背包问题, 设计一个有效算法找出最优解, 并说明算法的正确性.

算法设计:由题目所给的信息可以知道这种特殊的背包问题可以通过贪心算法得到最优解。

正确性证明:采用反证法,各物品依重量递增、价值递减序排列时,如果存在其他最优解使得在总限重条件下背包的价值更高,可以分为以下三种情形:

①物品个数比贪心算法得到的解更少,根据题目条件和贪心算法的性质,此情况不可能存在。

②物品个数比贪心算法得到的解相等,由于贪心算法选取的顺序是价值递减的顺序,此情况不存在。

③物品个数比贪心算法得到的解更多,假设存在的最优解与贪心算法的解去掉二者交集后,最优解中还剩两个或两个以上的物品 x j , x k x_j,x_k xj,xk,其总价值大于贪心算法选取的一个物品 x i x_i xi,即 v j + v k > v i v_j+v_k>v_i vj+vk>vi,但是由于 w i < w j < w k w_i<w_j<w_k wi<wj<wk以及 v i > v j > v k v_i>v_j>v_k vi>vj>vk因此一定有 v j + v k < v i + v j v_j+v_k<v_i+v_j vj+vk<vi+vj,与贪心算法的机制违背,此情况不成立。

综上所述,贪心算法可以找到此问题的最优解。

数据输入:物品重量数组 W [ 1.. n ] W[1..n] W[1..n],物品价值数组 V [ 1.. n ] V[1..n] V[1..n],背包限重 w w w

结果输出:布尔类型数组 O [ 1.. n ] O[1..n] O[1..n],值为 T r u e True True代表相应的物品装入背包,反之 F a l s e False False为放弃该物品。

伪码描述:

  1. O [ 1.. n ] ← { F a l s e , F a l s e . . . F a l s e } O[1..n]\leftarrow\{False,False...False\} O[1..n]{False,False...False}
  2. w e i g h t ← 0 weight\leftarrow0 weight0
  3. i ← 1 i\leftarrow1 i1
  4. w h i l e    T r u e    d o while\ \ True\ \ do while  True  do
  5. i f    w e i g h t + W [ i ] ≤ w / / 验证能否放入背包 if \ \ weight+W[i]≤w\quad//验证能否放入背包 if  weight+W[i]w//验证能否放入背包
  6. t h e n    O [ i ] = T r u e ;   i = i + 1 / / 放入背包并进入下一次循环 then\ \ O[i]=True;\ i=i+1\quad//放入背包并进入下一次循环 then  O[i]=True; i=i+1//放入背包并进入下一次循环
  7. e l s e    r e t u r n    O [ 1.. n ] else\ \ return\ \ O[1..n] else  return  O[1..n]

复杂度分析:该算法使用贪心算法,时间复杂度随输入规模一次线性增长,因此易得算法的时间复杂度是
W ( n ) = O ( n ) \begin{aligned} W(n)=O( n ) \end{aligned} W(n)=O(n)
算法需要一个布尔类型数组 O [ 1.. n ] O[1..n] O[1..n]来记录背包放入情况,因此空间复杂度是
S ( n ) = O ( n ) \begin{aligned} S(n)=O(n ) \end{aligned} S(n)=O(n)

4.2

将最优装载问题的贪心算法推广到两艘船的情形, 贪心算法仍然能产生最优解么? 若能, 给出证明. 若不能, 请给出反例.

证明:

如果使用贪心算法求解,必须把第一艘尽可能的装满,才能使总的装载量更多,第一艘船装载的方式只可能有一种最优解,即装载的物品都是以从轻到重的顺序装载,但是这样装并不一定得到最优解,例如下面这个例子:

假设${w_1,w_2,w_3,w_4,w_5}={10,20,30,40,50},c_1=50,c_2=50 ,贪心算法得到的解为 ,贪心算法得到的解为 ,贪心算法得到的解为{10,20},{30} ,这很显然不是最优解,最优解为 ,这很显然不是最优解,最优解为 ,这很显然不是最优解,最优解为{10,40},{20,30}$。

综上所述,将最优装载问题的贪心算法推广到两艘船的情形,贪心算法并不能保证产生最优解,该问题可以采用回溯法或动态规划等其他方法解决得到最优解。

4.3

Γ = 1 , . . . , n Γ = {1, . . . , n} Γ=1,...,n n n n 个字符的集合. 证明关于 Γ Γ Γ 的任何最优前缀码可以表示长度为 2 n − 1 + n ⌈ l o g n ⌉ 2n − 1 + n⌈log n⌉ 2n1+nlogn 位的编码序列. (提示: 先考虑树结构的编码, 再考虑叶结点对应字符的编码)

证明:

最优前缀编码所对应的编码二叉树是一棵完全二叉树,有 n n n个叶节点和 n − 1 n-1 n1个内节点,叶节点和内节点需要用 0 − 1 0-1 01区分,并通过对编码树前序遍历的结果来唯一确定编码树的结构,这个前序遍历结果有 2 n − 1 2n-1 2n1位。

叶节点所携带的数据使用二进制编码表示,因此每个叶节点需要 ⌈ l o g n ⌉ ⌈log n⌉ logn位编码,有 n n n个叶节点,因此共需要 n ⌈ l o g n ⌉ n⌈log n⌉ nlogn位编码来表示叶节点携带的数据。

综上,关于 Γ Γ Γ 的任何最优前缀码可以表示长度为 2 n − 1 + n ⌈ l o g n ⌉ 2n − 1 + n⌈log n⌉ 2n1+nlogn 位的编码序列。

4.4

给定 x x x 轴上 n n n 个闭区间. 去掉尽可能少的闭区间, 使得剩下的闭区间都不相交. 设计一个有效算法找出最优解, 并说明算法的正确性.

算法设计:首先对所有区间按照右端点升序的顺序进行排序,然后在排序后的结果中统计不相交的区间个数,最后将总区间个数减去不相交的区间个数计算出需删掉的区间个数。

正确性证明:由于首先对所有区间按照右端点升序的顺序进行了排序,需要尽可能保留更多的区间,因此这个问题就可以转化为 4.1 4.1 4.1中的特殊 0 − 1 0-1 01背包问题,具体证明不再赘述,详见 4.1 4.1 4.1

数据输入:闭区间个数 n n n n n n个闭区间组成的数组 x [ n ] [ 2 ] x[n][2] x[n][2]

结果输出:需要去掉的尽可能少的闭区间数 c u t N u m b e r cutNumber cutNumber

伪码描述:

  1. x ← Sort ⁡ ( x ) / / 首先对所有区间按照右端点升序的顺序进行排序 x \leftarrow \operatorname{Sort}(x) \quad / /首先对所有区间按照右端点升序的顺序进行排序 xSort(x)//首先对所有区间按照右端点升序的顺序进行排序
  2. c u t N u m b e r ← 0 / / 需要去掉的尽可能少的闭区间数 cutNumber\leftarrow0\quad//需要去掉的尽可能少的闭区间数 cutNumber0//需要去掉的尽可能少的闭区间数
  3. c u r v e ← 1 curve\leftarrow1 curve1
  4. f o r    i ← 2    t o    n    d o / / 遍历所有区间 for \ \ i \leftarrow 2 \ \ to \ \ n \ \ do\quad//遍历所有区间 for  i2  to  n  do//遍历所有区间
  5. i f    x [ i ] [ 1 ] ≥ x [ c u r v e ] [ 2 ] / / 验证区间是否重合 if \ \ x[i][1]≥x[curve][2]\quad//验证区间是否重合 if  x[i][1]x[curve][2]//验证区间是否重合
  6. t h e n    c u r v e = i / / 没有重合 then\ \ curve=i\quad//没有重合 then  curve=i//没有重合
  7. e l s e    c u t N u m b e r = c u t N u m b e r + 1 / / 存在重合,需要去掉 else\ \ cutNumber=cutNumber+1\quad//存在重合,需要去掉 else  cutNumber=cutNumber+1//存在重合,需要去掉
  8. r e t u r n    c u t N u m b e r return\ \ cutNumber return  cutNumber

复杂度分析:该算法使用贪心算法,时间复杂度随输入规模一次线性增长,因此易得算法的时间复杂度是
W ( n ) = O ( n ) \begin{aligned} W(n)=O( n ) \end{aligned} W(n)=O(n)
默认排序算法都在原数组上完成,因此算法只需要常数规模的存储空间,空间复杂度是
S ( n ) = O ( 1 ) \begin{aligned} S(n)=O(1 ) \end{aligned} S(n)=O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mitch311

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值