从买书那天算起,到今天已经过了半个多月。这段时间说短不短,如果是一本300多页的小说的话,我大概一天就能搞定(我的记录是一天一千多页《大唐双龙传》),但是到现在《编程之美》我只看了不到50页。虽然我不是天天看,但是一旦我看了一个问题之后,我就希望能够把这个问题在算法层面分析透,这份专注是我以前看《算法导论》或者上算法课的时候所不曾体会到的。究其原因,主要还是纯粹的理论流于枯燥,纯粹的应用不免肤浅,而这本书的定位刚刚好,既能够以应用带动算法的学习,又能够避免过于说教的风格。
1 问题描述及分析
本题所说的问题是微软每天为员工提供各种不同的饮料,如可乐,酸奶,豆浆,咖啡,绿茶……..(待遇不错啊,呵呵),饮料i的单位容量为Vi,其中每种饮料单个容量都是2的方幂,员工对饮料i的满意度为Hi,冰柜的总容量为V(每天必须装满),问题是如何组合现有的各种饮料,使总的满意度最高。
还是说一下我的第一印象,很显然这是一道最优化问题,但很容易想到这道题和线性规划的描述很符合,但是由于解线性规划的单纯型方法比较复杂,这里就不再讨论了。其次,回想一下经典的0-1背包问题,和本问题也有些相似,所不同的是0-1背包问题中,每件物品只能拿一次,而这里同一种饮料能拿多瓶;此外,原问题中每天供应的总量V是必须达到的(否则会有员工投诉?),所以不能够像0-1背包问题那样有让背包装不满的情况。这个条件实际上改变了我们对于最优解的搜索策略,因为容量为V的装饮料的冰柜每天早晨都必须是满的,所以即便有另一个使满意度最高但冰柜不满的组合我们也是不能选的。
其实我们可以稍微改变一下本题的条件,忽略原问题中的每种饮料单个容量都是2的方幂的条件,并允许冰柜不满的情况下求最大满意度的组合,希望可以使原问题的解决更富有一般性。
2 算法分析
2.1 动态规划算法
没有悬念,优化问题就用动态规划、贪心算法、分支限界轮番上阵就好了。设Opt(V’,i)表示从i到n-1种饮料中,Ci为第i种饮料可能的最大数量,算出总量为V’的方案中满意度之和的最大值。那么递归式就应该是:
Opt(V’,i)=max{ k * Hi+Opt(V’-Vi * k,i+1)}(k=0,1,2…,Ci,i=0,1,2…,n-1)
这里我觉得需要说明给出的饮料组合最终可以组合出V。
2.2 贪心算法
书中的贪心解法似曾相识,把信息按照饮料的容量排序(其中设我们有n0种容量为20的饮料):
Volume TotalCount Happiness
20 TC0_0 H0_0
… … …
20 TC0_1 H0_n0
… … …
21 TC1_0 H0_0
…
…
2M TCM_0 HM_0
…
然后按照下面的顺序进行贪心选择:
(1) 饮料总量为1,从容量为20的饮料中选出快乐指数最大的。
(2) 饮料总量为2,从容量为21的饮料中选出快乐指数最大的(设为H1),与容量为20的饮料中快乐指数最大的(设为H0),比较H1和2* H0,取出其中最大者为当前最佳选择
(3) 继续进行下去,直到求出Opt(V,0)
粗看一下,有些似曾相识。我们在买书问题的时候也曾面临将买书计划拆分,然后查表进行贪心选择。然而买书问题每次选择至多选M本书,而且每次选择只影响下一次选择,所以只需要把2M进行有限的拆分即可。
而本题则不尽相同,对于某种容量V’(以V’=11为例)来说,有两个问题:
1. 首先,我们需要察看所有拆分的可能性,找出其中最大者作为本次贪心选择的结果。其中,由于“每种饮料的单位容量都是2的方幂”,所以拆分结果仅考虑用小于V’的2的方幂来进行组合,即(计算式1)11=8+2+1,4+4+2=1,4+2+2+2+1,….,1+1+…+1。可以看到,对于V’我们至少可以“拆”出V’种组合(或许更多),即便我们把每次的计算结果用表格保存起来,我们的查找次数也至少是Ω(1+2+…+V’=V’2),空间复杂度也很高,并没有如数中说“简单很多”。而且,如果取消“每种饮料的单位容量都是2的方幂”的限制,拆分的结果就会变成(计算式2)11=10+1,9+2,…,5+5,5+5+1,5+4+2,…..,导致查找次数进一步增加。
2. 其次,让我们回到贪心选择的定义上来。由于贪心选择性,贪心算法的过程是每次选择都选取当前看来最好的结果,使得当达到最终状态时的结果刚好是最优解。而我们再看V’=11的例子,假设最优解是4+4+2+1,则我们曾经计算过的8就不是最优解的一部分,这就和贪心算法的精神不符,所以这个方法其实还是动态规划。
3 总结
动态规划解法很好,贪心算法有待商榷。其实这是正常的,因为通常情况下使用贪心算法的难点在于证明贪心选择性的存在,鉴于这本书的定位,我们不能苛责更多。但是这个问题和上一个问题(买书折扣问题)的贪心算法我觉得都过于草率。如果想让这本书成为经典,“微软面试”的噱头是远远不够的,精益求精的态度至关重要,有时候真的没必要把Deadline设置的那么紧迫,偶尔跳票追求质量也是理所应当,看看人家暴雪的“星际争霸2”跳票这么多年就知道了…….
4 《编程之美》本问题勘误
[1] P41,第七段,“Opt(V’,i)表示从第i,i+1,…,n-1,n种饮料…”,应该把n去掉,因为i的取值范围是[0,n-1]。
[2] P41,第八段,“Opt(V,n)”应该改为Opt(V,0)。
[3] P41,推导公式,应改为max{ … +Opt(V’-Vi * k i+1)}(…,i=n-2,n-1,……,0)
[4] P42,代码清单1-9,for (int i=0; i
本文由作者笔名:小小评论家 于 2023-03-26 17:18:46发表在本站,文章来源于网络,内容仅供娱乐参考,不能盲信。
本文链接: http://www.w2mh.com/show/65322.html