1.4 买书问题

 ㈠ 简要说明

感觉写的很乱,这里先做个简单的说明。对于共有m种书进行打折,总共要买n本。先将原来的折扣,转换成相对折扣(=最大折扣-原折扣)。用F(n)表示买n本书时,能得到最小相对折扣值,此时原折扣和=n*最大折扣-F(n),必然最大。显然,F(m)=0。贪心算法要能成立,就是要证明F(n)=F(n-m),或者找出, F(n)=F(n-m)在什么条件下才成立。

如果考虑书的具体种类,比如5本时的状态(a1, a2, a3, a4, a5)(递减排列)。可以证明,最优解的买书次数必然是a1次。其它的买书解法,都可以从解法(a5次5卷,a4-a5次4卷,…,a1-a2次1卷),通过几个 i+j => (i-1)+(j+1) (5 >= i > j+1, j>=1) 调整得到(觉得这个从图中看很直观,但不好证明)。通过判断i+j => (i-1)+(j+1)对相对折扣值的影响,就可以判断书上的解法是否一定成立。

㈡ 若书上的解法二是正确的,其是否具有通用性

原书的一个错误:

P32:“首先,对于大于5本的情况,我们不应该考虑按一本付钱的情况,因为没有折扣。”

这个结论不成立。因为即使没有折扣,也可能总折扣最大。事实上,对6本,拆分成1+5折扣为 125%(=5*25%+0)比拆分成4+2的折扣90%(=4*20%+2*10%)还要高。

能否采用书上的解法二,必须保证下面两个问题都成立:

(以下提到的贪心算法是否成立,均特指在不考虑书的具体种类时,贪心算法是否成立)

(1) 若贪心算法成立,是否可以按书中所述那样分组。

(2) 若贪心算法不成立,是否可以按贪心算法得到的结果上进行调整得到全局最优解。

考虑下面的2种折扣方案(只有买2种书时,折扣不同):

1

2

3

4

5

折扣

10%

15%(12.5%)

19%

23%

25%

总折扣

10%

30%(25%)

57%

92%

125%

为计算方便,我们先将各个折扣转成相对折扣(=最大折扣 - 原折扣)。“求折扣和最大”等同于“求相对折扣和最小”。

1

2

3

4

5

相对折扣

15%

10%(12.5%)

6%

2%

0

总相对折扣

15%

20%(25%)

18%

8%

0

从表很容易得出,对两种折扣方案,6-9本的最大折扣拆分方法都是:

6=1+5    7=2+5   8=4+4   9=4+5

都是在买8本时,贪心算法不成立。

但是,在买12本时,两种方案的最优拆分方法却不同。

2+5+5

4+4+4

2种书,折扣取10%时的总相对折扣

20%

24%

2种书,折扣取12.5%时的总相对折扣

25%

24%

结论1:贪心算法不成立时,简单的调整由贪心算法得到的结果,不能保证能得到全局最优解。

我们再考虑下面的折扣方案:

1

2

3

4

5

相对折扣

27%

10%

7%

3%

0

总相对折扣

27%

20%

21%

12%

0

这种折扣方案,对6-9本可以验证贪心算法是成立的。

如果只买 第1卷 4本,其它4卷各1本,即状态(4,1,1,1,1),按书中的拆分方法,得到:

5+1+1+1组合,总相对折扣为81%  而 2+2+2+2 这个组合总相对折扣为80%,比前面的更低。

结论2:在贪心算法成立时,按书中那样简单的分组不能保证得到全局最优解。

㈢  不考虑书的具体种类数

假设有m种书,共要买n本书,每次买的书的种类越多,每本书的折扣也越大。即m种时,折扣最大,用这个最大值减去每个折扣得到相对折扣。要使总折扣最大,只要总相对折扣最小。用F(n)表示总相对折扣的最小值(显然:F(1)>F(2)>… >F(m-1)>F(m)=0,若定义F(0)=0,则F(m)=F(0))。显然F(k*m)=0,由于F(m-1)是第二小的, F(k*m-1)=F(m-1) (k为自然数)。

可以采用的贪心算法:每次尽可能的买m本书。该贪心算法能找到最优解的话,则有:F(i)=F(i-m) (i>=m)。下面说明该等式在什么时候成立,即贪心算法在什么时候成立。

性质1:若对任意自然数i∈[ k, m+k-1] (自然数k>=m), F(i)=F(i-m)均成立,

则对任意 i >= k,F(i)=F(i-m) 恒成立。

证:由已知,当i∈ [ k, m+k-1] 时,命题F(i)=F(i-m)成立。

假设i=n (n>=m+k-1)时命题成立,则对任意i∈ [ k, n],F(i)=F(i-m)。

当i=n+1时,根据F(n)的定义及一次可买的书的卷数j(1 <= j <= m)可得:

F(n+1)= min{ F(j)+F(n+1-j)}  (1 <= j <= m,  k<= n+1-m <= n+1-j <= n)

=min{ F(j) + F(n+1-m-j)}

=F(n+1-m)

故i=n+1时命题仍成立。

因而,对任意 i >= k,F(i)=F(i-m)均成立

如果,k=m时上述命题成立,则对任意自然数i>=m,都有F(i)=F(i-m)= … =F(i%m)。

若要判断贪心算法(“每次尽可能买m本”)是否正确,只要判断本数为m到2*m-1时是否都符合贪心算法,而m本和2*m-1本都是一定符合的,实际上只要判断本数为m+1到2*m-2时是否都正确。

若设一次可买卷数为i(1<=i<=m),则剩余n-i,根据F(n-i)是否等于F(n-i-m),可将关于i的集合,分成两部分j、k,其中 F(n-j)=F(n-m-j),而F(n-k) !=F(n-m-k), 则有:

F(n-m)=min{F(i)+F(n-m-i)} <= min{ F(j) + F(n-m-j) }

若整数t满足F(n-m)=F(t)+F(n-m-t)并使等号成立,则t也属于j的集合,满足:F(n-t)=F(n-m-t)。

F(n)= min{ F(j)+F(n-j),F(k)+F(n-k)}

= min{ F(j) + F(n-m-j),  F(k) + F(n-k)}

>= min{ F(n-m),  F(k) + F(n-k)}

上式能取等号,必需满足下列条件之一:

① min{F(k)+F(n-k)} <= F(n-m)

② F(n-m)=F(t)+F(n-m-t) 且F(n-t)=F(n-m-t)  (1<= t <=m)

若t=m,F(n-m)=F(m)+F(n-2*m)=F(n-2*m),即当F(n-m)=F(n-2*m)时一定可以取等号。

对书上的折扣方案:

1

2

3

4

5

相对折扣

25%

20%

15%

5%

0

总相对折扣

25%

40%

45%

20%

0

F(6)=F(5)+F(1)=F(1)

F(7)=F(5)+F(2)=F(2)

F(8)=F(4)+F(4) < F(3) + F(5)

F(9)=F(4)

F(10)=F(5)

F(11)=min( F(6), F(3)+F(8) )=F(6)

F(12)=min( F(7), F(4)+F(8) )=F(7)

F(13) >= min( F(8), F(5)+F(8) )=F(8)  (而F(8)=F(5)+F(8),故可取等号)

购买本数为9到13时,都满足F(i)=F(i-5) (9<=i<=13),故i>=9时,均有 F(i)=F(i-5)。由于只有本数为8这一个例外,因而若采用贪心算法,能判断出是否将F(8)按F(3)计算,从而对结果进行调整,保证结果正确。

性质2: 存在整数k>=m,对任意整数 n >k, F(n)=F(n-m)恒成立。

证:

设买n-m本的最优解中,共有ai次每次买了i本书,则ai必定小于m,否则,ai次买i本,可以优化为i次买m本和ai-m次买i本。另外,ai <= i,否则,设j=ai > i,则j次每次买i本书,可以优化为i次每次买j本书。由于ai存在上界,可以假设t为i*ai(1<=i<=m-1)所有可能的乘积和中最大的,即t=max{sum(i*ai)}。

对整数n>t,如果F(n) != F(n-m) 则需要对F(n-m)的最优解:a1, a2, … am-1, am, 进行调整。对购买n本,能进行的调整只能是将am调整为0,将多出的(m+1)*am分散到其它的购买次数,否则的话,买n-m本书时也可以采用类似的调整,会得到更优解。此时 n <= t 这与 n>t矛盾。

因而,对任意整数 n> max{sum(i*ai)} (1<=i<=m-1) 总有:F(n)=F(n-m)

结论3:对任意的买书折扣方案(不考虑所买书的具体种类数),可以通过常数次计算,得到最优解。

当m=5,ai能取的最大值:

a1 为1(但取1时,其它的ai都要取0)

a2 为2(但如果a3不为0, 2+3 -> 5)

a3 为2  ( 3+3+3 -> 4+5)

a4 为4

因此 t=0*1+0*2+2*3+4*4=22

即对:对任意整数n>22 都有 F(n)=F(n-5)

又由于F(5*k)=0,F(5*k-1)=F(k-1)一定成立,因而对任何一种5卷的买书折扣方案,最多只要计算6、7、8、11、12、13、16、17、18、21和22这11个买法。

㈣ 考虑要买的书的具体种类:

根据各卷要买的数目,按大小降序排列,记为:(a1, a2, … am) (a1 >= a2 >= … >= am)。

并记书的种类编号为(d1, d2, … dm)。再记折扣方案为(b1, b2, … bm)(bi为一次买i本的折扣,b1 > b2 > … > bm)。

如果最优解购买次数大于a1,则必有一次买的书没有d1,假设这次买了di,共有k次没买d1但却买了di,则对a1次每次都买了d1,买了a1本d1的同时,最多只能买(ai-k)本di,由ai <= a1,可知这a1次购买时必有k次没有购买di,这k次购买时,每次可多买一本di,相对折扣和更低。也就是说,不在a1次购买的本都可分摊到a1次购买中,最终得到的相对折扣更少,这与已经是最优解矛盾,因而购买次数不大于a1。又由于要买a1本d1,每次不能买相同种类的,至少要买a1次,因而最优解购买次数为a1,这意味着每次都要买一本d1

若买法T:am次买m卷,am-1-am次买m-1卷,… a1-a2次买1卷,不是最优解,则与最优解相比较,必存在某本书由一次买i本书,转移到一次买j本书(m >= i > j >= 1,参考下面的直观图),转移的结果,组合i+j更改为(i-1)+(j+1),相对折扣改变了:bi-1 + bj+1 – (bi + bj) ,显然i=j+1时相对折扣没有改变,因而,i>j+1。若对所有的bi-1 + bj+1 – (bi + bj) (m >= i > j+1, j>=1)均大等于0,则说明买法T已经是最优解,因为对买法T的每一次调整都不会使相对折扣和减小。

对(a1, a2, a3, a4, a5),可以用下面的图形表示,5个长方形,各自的宽度表示要买的数目。纵方向的总高度就是每次要买的书的数目,由前面的证明可知,要购买a1次。如果将i次每次买了j卷,画一个宽为i,高为j的长方形,将以j=5,4,3,2,1顺序画的5个长方形合并。那么对买法T:a5次买5卷,a4-a5次买4卷,… a1-a2次买1卷,将所画的5个长方形合并后再根据高度划分界线,也可得到下面的图形,也就是说买法T对应的是初始状态。取出较高层i的一部分补到较低层k(要求补完后,从上到下每层的宽度仍是递增的,这相当于调整组合i+(k-1)=>(i-1)+k),通过多次这样的操作,可以得到其它的任意一种买法。比如减少第5层的的a5减少1,补到第4或第3或第2层(由于只能买a1次,第一层的长度a1不能改变)。从图中可以看出,如果t=a5 – ( (a1-a2)+ (a1-a3) + (a1-a4) )>0则第5层长度至少为t,也就是说至少要买t次5卷,再加上每次必须买1本d1卷,用动态规划求解时,只须用到4个变量即可。

书上的折扣方案:

1

2

3

4

5

相对折扣

25%

20%

15%

5%

0

总相对折扣

25%

40%

45%

20%

0

所有的 i+j => (i-1)+(j+1) (5 >= i > j+1, j>=1)

调整前组合

调整后组合

相对折扣改变值

5+3

=>

4+4

-5%

5+2

4+3

25%

5+1

4+2

35%

4+2

3+3

30%

4+1

3+2

40%

3+1

2+2

10%

如果上述的所有相对折扣改变值都是非负值,那么买法T就是最优解。但是表格中有一个例外,5+3 => 4+4  这个调整使相对折扣值是减小了。任何组合的调整结果都不可能出现5,但可以出现3,由于任何其它调整的相对折扣改变值都大于5%,因而不存在经过其它调整后再经过5+3 => 4+4调整仍能使相对折扣值减小。由于使相对折扣值变小的调整只有一个,经过这样的调整,肯定得到最优解。

结论4:书上的解法二是正确的,但不具有通用性。

编程之美读书笔记_1.4 买书问题相关推荐

  1. 编程之美读书笔记_1.1_让CPU占用率曲线听你指挥

    题目:写一个程序,让用户来决定Windows任务管理器(Task Manager)的CPU占用率.程序越精简越好,计算机语言不限.例如,可以实现下面三种情况:   1.    CPU的占用率固定在50 ...

  2. 编程之美 - 读书笔记 - 卖书折扣问题的贪心解法

    <编程之美>读书笔记(四):卖书折扣问题的贪心解法 每 次看完<编程之美>中的问题,想要亲自演算一下或深入思考的时候,都觉得时间过得很快,动辄一两个小时,如果再把代码敲一遍的话 ...

  3. 【编程之美/读书笔记】Chapter 1 游戏之乐

    这里就不写每个问题的题目了,只是记录一下自己的总结和心得. 1.1 让CPU占用率听你指挥 这个题目我刚接触的想法是和多核多线程要扯上关系的,因为自己写个死循环只能跑到CPU 35%左右的占用率,但是 ...

  4. Java并发编程之美读书笔记-并发编程基础2

    2019独角兽企业重金招聘Python工程师标准>>> 1.线程的通知与等待 Java中的Object类是所有类的父亲,鉴于继承机制,Java把所有类都需要的方法放到了Object类 ...

  5. 编程之美读书笔记2.1—求二进制数中1的个数

    解法一: 可以举一个8位二进制的例子.对于二进制操纵,我们除以一个2,原来数字就会减少一个0(向右移一位).如果除的过程中有余,那么久表示当前位置有一个1. 以10100010为例: 第一次除以2时, ...

  6. 编程之美--读书笔记--返回一个数组中所有元素被第一个元素除的结果

    笔试题目1:写一个函数,返回一个数组中所有元素被第一个元素除的结果 很多人会想到如下: void DivAarry(int *pArray,int size) { for(int i=size-1;i ...

  7. 编程之美读书笔记之-高效率的安排见面会

    问题一: n个同学,分别对m个招聘见面会感兴趣.为了满足所有学生的要求,hr希望让每个同学都能参加自己所有感兴趣的见面会.然后每个见面会的时间为t.问如何安排见面会能够使得所有见面会总的时间最短. 建 ...

  8. 中国象棋将帅问题java_编程之美读书笔记1.2——中国象棋将帅问题

    http://blog.csdn.net/pipisorry/article/details/36380669 问题:下过中国象棋的朋友都知道,双方的"将"和"帅&quo ...

  9. 编程之美 - 读书笔记 - 烙饼问题与搜索树

    前 面已经写了一些关于烙饼问题的简单分析,但因为那天太累有些意犹未尽,今天再充实一些内容那这个问题研究透.我想,通过这篇文章,我们就可以把这一类问题 搞懂.再遇到优化问题,如果我们想不到别的办法,就可 ...

  10. 设计模式之美读书笔记

    目录 设计模式之美 读书笔记5- 哪些代码看似面向对象,实际是面向过程编程? 读书笔记4- 封装.抽象.继承.多态分别解决了什么编程问题? 读书笔记3- 我们在讨论面向对象的时候,主要说的是什么? 读 ...

最新文章

  1. linux 文件查找及定位
  2. 计算机中的机器码就是二进制数,高电单片机习题(答案)
  3. flask socket连接mysql_Flask连接mysql,实现页面登录
  4. DVWA系列之21 存储型XSS分析与利用
  5. 14岁印度裔女孩因新冠潜在疗法赢得16万奖金,通过信息学筛出病毒先导分子
  6. python 多维数组的排序
  7. 窗口和元素的大小:offset client scroll
  8. 【渝粤教育】电大中专幼儿园课程论_1作业 题库
  9. AOP底层原理与注解配置详解
  10. 揭示地理数据分布规律的方法
  11. 【华为云技术分享】玩转小熊派BearPi(一)使用STM32CubeMX + HAL点亮一个LED
  12. 佳能c3320如何u盘打印_佳能打印机脱机无法打印怎么办 佳能打印机脱机状态如何解除【详解】...
  13. pom.xml中排除quartz包
  14. 缓存/内存型数据库 Redis
  15. 市场调研策划书_市场调研计划书模板
  16. Anaconda下载及安装(图文)
  17. 高通WLAN驱动分析
  18. dw计算机代码,DW-滚动文字代码.doc
  19. uniapp——头条小程序picker变黑色
  20. 大富翁源代码c语言,python版大富翁源代码分享.pdf

热门文章

  1. 【转】刘强东个人标签太明显,京东没有二号人物
  2. 企业微信url及生成授权链接
  3. 硬核!自动驾驶如何做数据标注?特斯拉EP3 Auto Labeling深度分析
  4. Debug无忧!清华校友打造Python调试神器!
  5. 【OpenGL游戏开发之一】MAC OS X And Win7 vs2010 搭建OpenGL
  6. JavaScript prototype原型实现继承
  7. 平面设计师okr_还在头疼怎么写OKR,这可能是最全的落地指导手册了
  8. 五一博客连载——毕业游记录
  9. Python统计学11——分位数回归
  10. xp系统共享计算机,win7系统计算机和xp系统计算机如何共享打印机