Tag:贪心;动态规划

题目

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

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

思路与算法

方法一

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

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

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

本数 最大折扣
6 5 * 25% + 0 = 1.25
2 * 5% + 4 * 20% = 0.9
3 * 10% *2 = 0.6
7 5 * 25% + 2 * 10% = 1.45
4 * 20% + 3 * 10% = 1.1
8 5 * 25% + 3 * 10% = 1.55
4 * 20% * 2 = 1.6
9 4 * 20% + 5 * 25% = 2.05
10 5 * 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)

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

编程之美1 哈利波特买书问题相关推荐

  1. 编程之美2.1 求二进制中1的个数

    最近一段的时间,一直在看编程之美之类的算法书籍,刚开始看编程之美,感觉到难度太大,有时候也不愿意去翻动这本书,不过,经过一段时间的修炼,我也彻底的喜欢上这本书了, 书中的算法涉及到很多方面,树,链表, ...

  2. 编程之美2.10:寻找数组中的最大值和最小值

    编程之美2.10: 对于一个有N个整数组成的数组,需要比较多少次才能把最大值和最小值找出来呢? 算法的思想是: 分而治之 测试数据:---------------------------------- ...

  3. 2017“编程之美”终章:AI之战勇者为王

    编者按:8月15日,第六届微软"编程之美"挑战赛在选手的火热比拼中圆满落下帷幕."编程之美"挑战赛是由微软主办,面向高校学生开展的大型编程比赛.自2012年起, ...

  4. Java 并发编程之美:并发编程高级篇之一-chat

    借用 Java 并发编程实践中的话:编写正确的程序并不容易,而编写正常的并发程序就更难了.相比于顺序执行的情况,多线程的线程安全问题是微妙而且出乎意料的,因为在没有进行适当同步的情况下多线程中各个操作 ...

  5. Java 并发编程之美:并发编程高级篇之一

    借用 Java 并发编程实践中的话:编写正确的程序并不容易,而编写正常的并发程序就更难了.相比于顺序执行的情况,多线程的线程安全问题是微妙而且出乎意料的,因为在没有进行适当同步的情况下多线程中各个操作 ...

  6. 编程之美1:那些关于1的个数的经典面试题

    那些关于1的个数的经典面试题 好长时间没有练算法了,笔试题一做,发现非常吃力,所以近日来找来<编程之美>一书来看看练练.为了激励自己多练,楼楼可能会出个专栏什么的,感兴趣的同学我们可以一起 ...

  7. 中国象棋将帅问题java_编程之美:中国象棋将帅问题

    Author: Fox 晚上没有加班,打游戏打到9点过,后面就又看了一道<编程之美>的题目<中国象棋将帅问题>. 题目:下过中国象棋的朋友都知道,双方的"将" ...

  8. 瓷砖覆盖地板c语言程序,编程之美4.2 瓷砖覆盖地板

    题目 这个题目的题意很容易理解,在一个N*M的格子里,我们现在有两种类型的 砖块,1 * 2 和 2 * 1,问一共有多少种方案,可以将整个N*M的空间都填满. 最简单的例子就是下面的了: 编程之美中 ...

  9. 编程之美:编程判断两个链表是否相交

    1.问题描述 给出两个单向链表的头指针,比如h1.h2,判断两个链表是否相交.编程之美为了简化问题,假设两个链表均不带环. 如下图: 2.分析与解法 解法一:直观法,先判断第一个链表的每个节点是否在第 ...

  10. 编程之美2.15 二维数组最大子数组的和(数组下标从(1,1)开始)

          首先,我们看到这篇文章的题目,我们就会想到之前的那个题目 -- 连续子数组最大和问题.这个问题无疑就是把原问题扩展到二维的情况.       想起来这个问题也不是很难,我们可以求解一维矩阵 ...

最新文章

  1. 对话通信原理系列专题目录
  2. JavaWeb中使用session保持用户登录状态
  3. 从零开始的AI·吃透kNN算法,学完我悟了(附实例代码)
  4. 中国冶金行业投资战略及未来发展形势研究报告2021版
  5. 信息报送不及时整改措施_工商年报如何报送?原来这才是正确打开方式
  6. 【海洋女神原创】一个完整的Installshield安装程序实例—艾泽拉斯之海洋女神出品(二) --基本设置二...
  7. SAP 电商云 Spartacus UI 的 style library 介绍
  8. 背景图层和普通图层的区别_ps:图层有多少种类?我已经列出来了,学不学就看你自己了...
  9. vue中class绑定函数
  10. 解决tomcat控制台以及localhost Log和Catalina Log乱码问题
  11. 使用 Windows Phone 执行模型的最佳做法
  12. java获取网络图片_做个看图片的App玩玩_第一篇
  13. 如何在 Mac 上自动启用隐藏式字幕?
  14. HTML URL编码
  15. oracle滚动打补丁,ORACLE打补丁的方法和案例
  16. 计算机考试用户注册,全国计算机等级考试(NCRE)
  17. 基于镶嵌数据集制作地貌晕眩图
  18. 产品经理如何营销自己
  19. 如何解决模具折弯尺寸不稳定?
  20. 基于TCP的网络聊天室实现(C语言)

热门文章

  1. Retrofit 使用 DELETE 方式
  2. lof基金溢价率php源码,一文读懂LOF基金套利策略 LOF是球友们很喜欢的一类基金,这类基金不仅可以在场内进行高效买卖,而且还可以进行折溢价套利。不过这里面牵扯到很多细节,... - 雪球...
  3. 眼血管分割matlab,视网膜血管分割matlab
  4. Bloodsucker ZOJ - 3551
  5. 蓝的成长记——追逐DBA(11):回家后的安逸,晕晕乎乎醒了过来
  6. 农历php,php 阴历-农历-转换类代码
  7. Linux解决中文乱码问题及LANG与NLS_LANG的区别
  8. Swift零基础学习之用TableView做个景点App
  9. sql server 2000收缩数据库【极简操作】
  10. 电力猫服务器的网页,电力猫怎么配对?快速配置电力猫的图文教程