重新开始战斗03-编程之美-买书问题

问题描述:

由于《哈利波特》系列相当畅销,店长决定通过促销活动来回馈读者。上柜的《哈利波特》瓶装本系列中,一共有5卷。假设每一卷单独销售均需8欧元。如果读者一次购买不同的两卷,就可以扣除5%的费用,三卷更多。具体的折扣如下:

 

本数                     折扣

 2                         5%

 3                         10%

 4                         20%

 5                         25%


每本书只能享受一种折扣。例如买5本不同的书,可以享受折扣25%,也可以享受(5%+10%),或者(0+20%),甚至只要你愿意,可以享受0折扣(分开买....);有如买了3本1卷,2本2卷,不能享受25%的折扣,因为上述的折扣只是针对不同的卷册时才行。

问题是,如何进行买书花费最少(根据要买的书,进行折扣的组合,时折扣最大)?

 

书上列出了一个10本书以内的表。发现5+3组合小于4+4的组合,由于这样的情况出现,使得我们不能用传统的贪心算法解决该问题(每次贪心25%折扣)。


结合书的讲解,以及自己的思考,提出下面的算法:

传统的贪心算法:首先每本书的价格一样,那么意思就是买(1,1,3,2,1)与买(1,1,1,2,3)或者(3,2,1,1,1)没有区别。因此我们按降序排序(为了方便我们的贪心,因为5本不同的情况必然小于4本不同,4本不同又小于3本不同……)。

按降序排序后,我们要买书的情况为:

 

(Y1,Y2,Y3,Y4,Y5)                                   (Y1≥Y2≥Y3≥Y4≥Y5)

传统贪心,贪心局部最优——总是选择25%的折扣,如果没有5本不一样,则选择次大的20%,如果没有4本不一样的,选择10%,……

因此:

剩余

第一次选择:Y5次5本不同:    Y5*(1,1,1,1,1)   (Y1-Y5,Y2-Y5,Y3-Y5,Y4-Y5,0)

第二次选择:Y4-Y5次4本不同:Y4-Y5*(1,1,1,1,0) (Y1-Y4,Y2-Y4,Y3-Y4,0,0)

第三次选择:Y3-Y4次3本不同:Y3-Y4*(1,1,1,0,0) (Y1-Y3,Y2-Y3,0,0,0)

第三次选择:Y2-Y3次3本不同:Y2-Y3*(1,1,0,0,0) (Y1-Y2,0,0,0,0)


但是4+4的组合大于5+3,因此我们不能这么简单的贪心。应该是把K次5本不同与K次3本不同转化为2K次4本不同,由此,结合上面的传统贪心,就应该以Y5与Y3-Y4的最小者为K,那么本来Y4-Y5次4本不同就变成了Y4-Y5+2K次,其他不变。我也根据这样的贪心策略写出了程序,核心代码如下:

double MinPrice(int *Book,int n)

{

       ShellSort(Book,n);                                    // 采用希尔排序使输入排序

       intmin = (Book[5] < Book[3] - Book[4])?Book[5]:(Book[3] - Book[4]); // 找到K

 

       doubleminPrice;

       minPrice= 8*5*0.25*(Book[5]-min) +

              8*4*0.2*(Book[4]-Book[5]+2*min)+

              8*3*0.1*(Book[3]-Book[4]-min)+

              8*2*0.05*(Book[2]-Book[3]);

       intsum = 0;

       for(inti = 1; i < 6; i++)

              sum+= Book[i];

       returnsum*8 - minPrice;

}

输出结果:


答案和书上的结果一样,起组合形式4+4+4+4+4+2+1,这种组合的结果就是151.2。但是书上没有给出证明,即5+3转换为4+4总是最优的。

 

我尝试证明一下:

假设我们一共买X本书,暂且不考虑X本的分布。如果这X本书中存在(2,2,2,1,1)的组合,那么,一定存在5+3的组合,即(1,1,1,1,1)与(1,1,1,0,0)。

但是对于(1,1,1,1,1)与(1,1,1,0,0),一定可以分为(1,1,1,1,0)与(1,1,1,1,0),即4+4组合。因此不管是采用5+3还是4+4,总是剩下X-8本书,而且,这X-8本书的分布一定是一样的,因为不管是(1,1,1,1,1)与(1,1,1,0,0)还是(1,1,1,1,0)与(1,1,1,1,0),都是减少了(2,2,2,1,1)。

因此0.35+F(X-8)max < 0.4+F(X-8)max

问题的关键在于不管是5+3与4+4之间的转换,始终不会破坏剩余书本的分布。

结论:5+3转换为4+4总是最优!


动态规划

要用动态规划解答首先要找到,动态规划的递归公式,因为动态规划是自顶向下层层递归,然后自底向下层层解答!最后根据底层结论求解最后结果。

五卷书的价格相同都是8欧元,所以购买(1,0,0,0,0)跟(0,1,0,0,0)效果一样。这里就可以简化为,让所购买书按照本书递增(递减),从而方便讨论。

要处理的参数为购买每种卷的个数,所以递归一定跟这五个参数相关。可以把参数按照从小到大顺序排列。讨论不为0的参数的个数,从而求出所有可能的折扣种类。然后从当前折扣种类中取价格最小值。

        (X1,X2,X3,X4,X5)代表购买每卷的个数,F(X1,X2,X3,X4,X5)代表最低价格。X1< X2 < X3 < X4 < X5

                            F(X1,X2,X3,X4,X5)=0  ;当所有参数都为0的情况(这也是退出递归的出口)

                             F(X1,X2,X3,X4,X5)= min{

 5*8*(1-25%) +F(X1-1,X2-1,X3-1,X4-1,X5-1) //参数全部  > 0

 4*8*(1-20%) +F(X1,X2-1,X3-1,X4-1,X5-1)   //x2 > 0

 3*8*(1-10%) +F(X1,X2,X3-1,X4-1,X5-1)        //x3> 0

 2*8*(1-5%) +F(X1,X2,X3,X4-1,X5-1)             //x4> 0

 8 +F(X1,X2,X3,X4,X5-1)                                  //x5> 0

 }



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值