现在的位置: 首页 > 综合 > 正文

编程之美 1.4 买书问题

2018年01月19日 ⁄ 综合 ⁄ 共 2293字 ⁄ 字号 评论关闭

1.4 买书问题 

题目描述:

在 节假日的时候,书店一般都会做促销活动。由于《哈利波特》系列相当畅销,店长决定通过促销活动来回馈读者。在销售的《哈利波特》平装本系列中,一共有五 卷,用编号0, 1, 2, 3, 4来表示。假设每一卷单独销售均需要8欧元。
如果读者一次购买不同的两卷,就可以扣除5%的费用,三卷则更多。假设具体折扣的情况如下:
本数          折扣
2           5%
3          10%
4          20%
5          25%
在一份订单中,根据购买的卷数以及本书,就会出现可以应用不同折扣规则的情况。
但是,一本书只会应用一个折扣规则。比如,读者一共买了两本卷一,一本卷二。
那么,可以享受到5%的折扣。另外一本卷一则不能享受折扣。
如果有多种折扣,希望能够计算出的总额尽可能的低。
要求根据这样的需求,设计出算法,能够计算出读者所购买一批书的最低价格。

解法一:贪心策略

  当书的数目N<5时,直接按照折扣购买
  当书的数目N>5时,按最大折扣购买;
情况如下:
先找出是所有书中5种不同的书,如果有则按照5本书折扣价购买
其次找出剩余书中所有4种书,如果有则按照4本书的折扣价购买
再找出剩余书中所有3种书,如果有则按照3本书的折扣价购买 
最后在剩余书中找出所有2种书,如果有则按照2本书的折扣价购买

剩下的书则按照全价购买。


如果按照这种方法(贪心法)存在反例,
比如买8本书时,可以拆成5+3,折扣为1.55;
也可以拆成4+4,折扣为1.6 
这种两种情况组合中都包括,通过选择一个折扣最低的可以排除掉第一种情况。

结论:贪心策略不可取 

解法二:动态规划

五卷书的价格相同都是8欧元,所以购买(1,2,3,5,4)跟(5,4,3,2,1)相同。
让所购买书按照本书递减讨论。

(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) //X5>=1
     4*8*(1-20%) +F(X1-1,X2-1,X3-1,X4-1,X5)   //x4>=1
  3*8*(1-10%) +F(X1-1,X2-1,X3-1,X4,X5)     //x3>=1
   2*8*(1-5%) +F(X1-1,X2-1,X3,X4,X)         //x2>=1
     8 +F(X1-1,X2,X3,X4,X5)                   //x1>=1

  }

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX=100000000;//定义一个最大值,相当于取最小值时忽略这个位置的值

bool cmp(double a,double b)
{
	return a>b;
}

 double Min(double a, double b, double c, double d, double e)//返回最小值
 {
            double nn[5]={a,b,c,d,e};           
            sort(nn,nn+5,cmp);//从大到小排序 
            return nn[4];
 }
 
double f(int x1,int x2,int x3,int x4,int x5)//动态规划
{
            int n[5]={x1,x2,x3,x4,x5};
            sort(n,n+5,cmp);//从大到小排序 
            
            x1=n[0];x2=n[1];x3=n[2];x4=n[3];x5=n[4];
            if (x5>=1) 
            {
                return Min(
						8.0+f(x1-1,x2,x3,x4,x5),
                		2*8*0.95+f(x1-1,x2-1,x3,x4,x5),
                    	3*8*0.9+f(x1-1,x2-1,x3-1,x4,x5),
                    	4*8*0.8+f(x1-1,x2-1,x3-1,x4-1,x5),
                    	5*8*0.75+f(x1-1,x2-1,x3-1,x4-1,x5-1));
            }
            else if (x4>=1)
            {
                return Min(
						8.0+f(x1-1,x2,x3,x4,x5),
                		2*8*0.95+f(x1-1,x2-1,x3,x4,x5),
                    	3*8*0.9+f(x1-1,x2-1,x3-1,x4,x5),
                    	4*8*0.8+f(x1-1,x2-1,x3-1,x4-1,x5),
						MAX); 
            }
            else if (x3>=1)
            {
                return Min(
						8.0+f(x1-1,x2,x3,x4,x5),
                		2*8*0.95+f(x1-1,x2-1,x3,x4,x5),
                    	3*8*0.9+f(x1-1,x2-1,x3-1,x4,x5),
						MAX,MAX);
            }
            else if (x2>=1)
            {
                return Min(
						8.0+f(x1-1,x2,x3,x4,x5),
                		2*8*0.95+f(x1-1,x2-1,x3,x4,x5),
						MAX,MAX,MAX);
            }
            else if (x1>=1)
            {
                return 8.0+f(x1-1,x2,x3,x4,x5);	
            }
            else//都为0
            {
                return 0;
            }
        }
  
int  main()
{
       //int n1[5] = {3,4,2,1,0};
       int n1[5] = {2,2,2,1,1};
       //5+3=5*8*0.75+3*8*0.9=51.6
       //4+4=4*8*0.8+4*8*0.8=51.2
       double solution =f(n1[0],n1[1],n1[2],n1[3],n1[4]);
       cout<<"所花费的最少的钱为:"<<solution<<endl;  
}

抱歉!评论已关闭.