编程之美1 哈利波特买书问题
admin
2024-02-06 22:12:54
0

Tag:贪心;动态规划

题目

《哈利波特》系列一共有五卷,假设每一卷单独销售均需8欧元。如果读者一次购买不同的两卷,就可以扣除5%的费用,三卷则更多。假设具体折扣的情况如下:
本数 2 折扣 5%
本数 3 折扣 10%
本数 4 折扣 20%
本数 5 折扣 25%
在一份订单中,根据购买的卷数及本数,就会出现可以应用不同折扣规则的情况。但是,一本书只会应用一个折扣规则。比如,读者一共买了两本卷一、一本卷二。那么可以享受到5%的折扣。另外一本卷一则不能享受折扣。如果有多种折扣,希望计算出的总额尽可能的低。

需要根据以上需求,设计出算法,能够计算出读者所购买的一批书的最低价格。

思路与算法

方法一

先考虑贪心算法,如果每次选最大的折扣,是否总折扣就是最大的呢?可以列一个表格先计算1-5本(假设都能获得最大折扣,即买的都是不同卷的书籍):

本数最大折扣
22 * 5% = 0.1
33 * 10% = 0.3
2 * 5% + 0 = 0.1
43 * 10% + 0 = 0.3
2 * 5% * 2 = 0.2
4 * 20% = 0.8
52 * 5% + 3 * 10% = 0.5
4 * 20% + 0 = 0.8
5 * 25% = 1.25

可以看到在5本之内都是选择最大的折扣,那如果继续计算也是这样的结果吗?

本数最大折扣
65 * 25% + 0 = 1.25
2 * 5% + 4 * 20% = 0.9
3 * 10% *2 = 0.6
75 * 25% + 2 * 10% = 1.45
4 * 20% + 3 * 10% = 1.1
85 * 25% + 3 * 10% = 1.55
4 * 20% * 2 = 1.6
94 * 20% + 5 * 25% = 2.05
105 * 25% * 2 = 2.5

可以发现,在本数=8时,贪心使用最大的折扣并不能获得最大的优惠,所以,我们可以把所有的本数分解为10以内的来解决。

方法二

可以使用动态规划的方式来解决:
假设(Y1,Y2,Y3,Y4,Y5),其中Yn表示购买第n卷书的数量,Y1,Y2,Y3,Y4,Y5是购买第1,2,3,4,5卷书数量的重排列,满足Y1>=Y2>=Y3>=Y4>=Y5,用F(Y1,Y2,Y3,Y4,Y5)表示买书的最大折扣,则:
F(Y1,Y2,Y3,Y4,Y5)=0if(Y1=Y2=Y3=Y4=Y5=0)F(Y1,Y2,Y3,Y4,Y5)=min{x=5∗8∗(1−0.25)+F(Y1−1,Y2−1,Y3−1,Y4−1,Y5−1)if Y5>=1x=4∗8∗(1−0.2)+F(Y1−1,Y2−1,Y3−1,Y4−1,Y5)if Y4>=1x=3∗8∗(1−0.1)+F(Y1−1,Y2−1,Y3−1,Y4,Y5)if Y3>=1x=2∗8∗(1−0.05)+F(Y1−1,Y2−1,Y3,Y4,Y5)if Y2>=1x=1∗8+F(Y1−1,Y2,Y3,Y4,Y5)if Y1>=1F(Y1, Y2, Y3, Y4, Y5) = 0 \quad if(Y1 = Y2 = Y3 = Y4 = Y5=0) \\ F(Y1, Y2, Y3, Y4, Y5) = min{\begin{cases} & x = 5 * 8 * (1 - 0.25) + F(Y1 - 1, Y2 - 1, Y3 - 1, Y4 - 1, Y5 - 1) \text { \quad if } Y5>= 1\\ & x = 4 * 8 * (1 - 0.2) + F(Y1 - 1, Y2 - 1, Y3 - 1, Y4 - 1, Y5) \text { \quad if } Y4>= 1\\ & x = 3 * 8 * (1 - 0.1) + F(Y1 - 1, Y2 - 1, Y3 - 1, Y4, Y5) \text {\quad if } Y3>= 1\\ & x = 2 * 8 * (1 - 0.05) + F(Y1 - 1, Y2 - 1, Y3, Y4, Y5)\text { \quad if } Y2>= 1\\ & x = 1 * 8 + F(Y1 - 1, Y2, Y3, Y4, Y5)\text { \quad if } Y1>= 1 \end{cases}} F(Y1,Y2,Y3,Y4,Y5)=0if(Y1=Y2=Y3=Y4=Y5=0)F(Y1,Y2,Y3,Y4,Y5)=min⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧​​x=5∗8∗(1−0.25)+F(Y1−1,Y2−1,Y3−1,Y4−1,Y5−1) if Y5>=1x=4∗8∗(1−0.2)+F(Y1−1,Y2−1,Y3−1,Y4−1,Y5) if Y4>=1x=3∗8∗(1−0.1)+F(Y1−1,Y2−1,Y3−1,Y4,Y5)if Y3>=1x=2∗8∗(1−0.05)+F(Y1−1,Y2−1,Y3,Y4,Y5) if Y2>=1x=1∗8+F(Y1−1,Y2,Y3,Y4,Y5) if Y1>=1​

代码

package arithmetic;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class Main {// 贪心算法private static double discount1(double number) {switch((int) number) {case 0:return 0;case 1:return 8;case 2:return 8 * 2 * (1 - 0.05);case 3:return 8 * 3 * (1 - 0.1);case 4:return 8 * 4 * (1 - 0.2);case 5:return 8 * 5 * (1 - 0.25);default:// 当本数为8时的最优策略是4 + 4 本分配if(number % 5 == 3){return 8 * 4 * (1 - 0.2) * 2 + discount1(number - 8);} else {return 8 * 5 * (1 - 0.25) + discount1(number - 5);}}}// 动态规划private static void rerank(double[] n, int length) {double temp;int i = length - 1;for(; i > 0; i--) {for(int j = 0; j < i; j++) {if(n[j] < n[j + 1]) {temp = n[j];n[j] = n[j + 1];n[j + 1] = temp;}}}}private static double MAX_VALUE = 12138;private static double min(double x1, double x2, double x3, double x4, double x5) {double[] n = {x1, x2, x3, x4, x5};rerank(n, 5);return n[4];}private static double discount2(double x1, double x2, double x3, double x4, double x5){double[] n =  {x1,x2,x3,x4,x5};rerank(n, 5);if(n[4] > 0) {return min(5 * 8 * (1 - 0.25) + discount2(n[0] - 1, n[1] - 1, n[2] - 1, n[3] - 1, n[4] - 1),4 * 8 * (1 - 0.2) + discount2(n[0] - 1, n[1] - 1, n[2] - 1, n[3] - 1, n[4]),3 * 8 * (1 - 0.1) + discount2(n[0] - 1, n[1] - 1, n[2] - 1, n[3], n[4]),2 * 8 * (1 - 0.05) + discount2(n[0] - 1, n[1] - 1, n[2], n[3], n[4]),8 + discount2(n[0] - 1, n[1] , n[2], n[3], n[4]));} else if(n[4] == 0 && n[3] > 0) {return min(MAX_VALUE,4 * 8 * (1 - 0.2) + discount2(n[0] - 1, n[1] - 1, n[2] - 1, n[3] - 1, n[4]),3 * 8 * (1 - 0.1) + discount2(n[0] - 1, n[1] - 1, n[2] - 1, n[3], n[4]),2 * 8 * (1 - 0.05) + discount2(n[0] - 1, n[1] - 1, n[2], n[3], n[4]),8 + discount2(n[0] - 1, n[1] , n[2], n[3], n[4]));} else if(n[4] == 0 && n[3] == 0 && n[2] > 0) {return min(MAX_VALUE, MAX_VALUE,3 * 8 * (1 - 0.1) + discount2(n[0] - 1, n[1] - 1, n[2] - 1, n[3], n[4]),2 * 8 * (1 - 0.05) + discount2(n[0] - 1, n[1] - 1, n[2], n[3], n[4]),8 + discount2(n[0] - 1, n[1] , n[2], n[3], n[4]));} else if(n[4] == 0 && n[3] == 0 && n[2] == 0 && n[1] > 0) {return min(MAX_VALUE, MAX_VALUE, MAX_VALUE,2 * 8 * (1 - 0.05) + discount2(n[0] - 1, n[1] - 1, n[2], n[3], n[4]),8 + discount2(n[0] - 1, n[1] , n[2], n[3], n[4]));} else if(n[4] == 0 && n[3] == 0 && n[2] == 0 && n[1] == 0 && n[0] > 0) {return min(MAX_VALUE, MAX_VALUE, MAX_VALUE, MAX_VALUE,8 + discount2(n[0] - 1, n[1] , n[2], n[3], n[4]));} else {return 0;}}public static void main(String[] args) {System.out.println(discount2(2, 3, 4, 5, 6));System.out.println(discount1(12));}
}

时间复杂度

贪心算法:O(n)
动态规划:O(Y1 * Y2 * Y3 * Y4 * Y5)

不过这两种方法的输入是不一样的,我暂时还没想好贪心法如果输入是每种书的购买数量该怎么做

相关内容

热门资讯

初中演讲比赛规则? 初中演讲比赛规则?分为演讲选手规则,比如情绪饱满,仪表庄重,比赛规则,比如按照抽签顺序,评分规则去掉...
金色的鱼钩主要内容 金色的鱼钩主要内容这篇课文叙述了长征途中一位炊事班长接受党组织交给的任务,照顾三个生病的小战士过草地...
罗贯中在《三国演义》中使用昀独... 罗贯中在《三国演义》中使用昀独特的哪些手法?《三国演义》采用夸张手法表现人物形象。罗贯中在《三国演义...
呼吸困难是什么原因造成的? 呼吸困难是什么原因造成的?可能是由于鼻炎,造成鼻子不通气,在你呼吸的时候,自然就会感觉到呼吸困难,但...
比心怎么形容? 比心怎么形容?比心,网络流行词,也作“笔芯”,一种网络流行手势,指用双手比出一个爱心的形状,来表达对...
抽动症的症状,有哪些? 抽动症的症状,有哪些?我家孩子从小乖巧懂事,聪明伶俐,最近一段时间不知道怎么了,老是眨眼,耸肩,去医...
2-8人去张家界旅游团五天四晚... 最近我跟几个朋友计划了一趟张家界五天四晚的旅行,原本以为自由行最省心,结果发现行程安排、门票预订、交...
北京跟团游5天4晚旅游团,旅行... 北京,这座融合了古老与现代、传统与创新的城市,一直是我心中的向往之地。为了能让这次旅行更加顺利和充实...
什么是童年梦? 什么是童年梦?或者什么意思呢?》 回答: 代表着真爱,那是最纯洁的爱,要好好去追那个女孩,好好珍惜。...
“90版50元人民币”景色再现... 7月4日,受黄河上游水库泄洪的影响,位于秦晋峡谷的陕西黄河壶口瀑布迎来了今年最大水流量,瞬时水流量接...
哪部小说的章节是妈妈的秘密 哪部小说的章节是妈妈的秘密 奇迹的【和美女老师同居】第583章 妈妈的秘密
什么是直觉? 什么是直觉?我想问一下,直觉是什么?它是使用右脑来控制的吗?举个例子来说明什么的直觉,最好是学习上的...
治疗严重失眠偏方有用吗?... 治疗严重失眠偏方有用吗?...我妈妈晚上22点多就睡,睡到1点就会自然醒,到5点多才有睡意。我妈妈她...
和孩子离别的句子? 和孩子离别的句子?1、风筝升天,禁不住丝线缠绵;大雁南飞,依然频频回望。岁月易老,世事易变,流逝的岁...
历史上有谁因高人指点自己改变了... 历史上有谁因高人指点自己改变了自己的命运? 明代袁黄袁了凡,俞都俞敬意推荐《了凡四训》《俞敬意遇灶...
明末文坛领袖钱谦益在历史上到底... 明末文坛领袖钱谦益在历史上到底是一个怎样的人?他是一个贪生怕死,为了生不要自己的脸面,不要自己的尊严...
斗罗大陆142话什么时候出?求... 斗罗大陆142话什么时候出?求时间应该是7月份出吧
王迅让罗志祥洗脚是哪一集 王迅让罗志祥洗脚是哪一集王迅让罗志祥洗脚是《极限挑战》第二季的的第三期,首播时间是2016年5月1日...