买书动态规划java_动态规划——买书问题

转载自CSDN 朱超迪,链接:http://blog.csdn.net/q623702748/article/details/51592427

在朱超迪的原代码上做了一些修改

问题描述:

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

本数     折扣

2            5%

3           10%

4           20%

5           25%

在一份订单中,根据购买的卷数及本数,就会出现可以应用不同折扣规则的情况。但是,一本书只会应用一个折扣规则。比如,读者一共买了两本卷一,一本卷二。那么,可以享受到5%的折扣。另外一本卷一则不能享受折扣。如果有多种折扣,希望计算出的总额尽可能的低。

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

思路分析:

看到这个题目,任何人一开始想到的都是希望让书本尽可能享受高折扣。但是随着书本数目大于5本的时候,享受的总折扣就会相应出现了变化。

举个例子, 当输入的数据为(2,2,2,1,1)的时候,如果按照享受最高折扣计算,那么对应的折扣策略就会拆分变成(1,1,1,1,1)和(1,1,1,0,0)两种,总价格变为8×0.75×5+8×0.9×3= 51.6欧元。但是如果我们变一下策略,选择4+4,购买序列变为(1,1,1,1,0)以及(1,1,1,0,1),那么总共花费8×0.8×5+8×0.8×5=51.2欧元。

看到这里,我们已经可以使用动态规划通过计算总折扣数来计算最优惠价格,当然,也可以采用优化的贪心算法来实现,因为贪心算法求解这类题目都是近似解,与最优解相近。

解题:

先将现有条件转换一下(用百分比表示书本单价的多少倍):

本数

相对于书本单价的百分比

1

100%

2

190%

3

270%

4

320%

5

375%

具体说明一下吧:

当只有一本书的时候,没有折扣,所以为100%,即原价8欧元购买;

当有两本不同的书本,享有5%折扣,原本总价为200% ,减掉每本5%折扣,为190%,即15.2欧元;

当有三本不同的书本,享有10%折扣,原本总价为300%,减掉每本10%折扣,为270%,即21.6欧元;

当有四本不同的书本,享有20%折扣,原本总价为400%,减掉每本的20%折扣,为320%,即25.6欧元;

当有五本不同的书本,享有25%折扣,原本总价为500%,减掉每本的25%折扣,为375%,即30欧元;

以上折扣数据存放在minDis[6]中

即minDIs[6] = {0 , 1,1.9 , 2.7 , 3.2 , 3.75 };

根据上述条件描述,我们可以定义出一条状态转移方程(核心):

F[Y1,Y2,Y3,Y4,Y5] = min{   //定量 + 变量  的组合

8*minDis[5]+F(Y1-1,Y2-1,Y3-1,Y4-1,Y5-1),

8*minDis[4]+F(Y1-1,Y2-1,Y3-1,Y4-1,Y5),

8*minDis[3]+F(Y1-1,Y2-1,Y3-1,Y4,Y5),

8*minDis[2]+F(Y1-1,Y2-1,Y3,Y4,Y5),

8*minDis[1]+F(Y1-1,Y2,Y3,Y4,Y5)

}

其中必须保证Y1>=Y2>=Y3>=Y4>=Y5,这样才不会出现更多的冗余数据。例如:(2,2,2,1,1)和(1,2,1,2,2)虽然不同,但是结果都是一样的。

下面是这个问题的代码(我个人修改过了):

1 //买书问题

2

3 float discount[6] = {0,1,1.9,2.7,3.2,3.75};4 float price[6][6][6][6][6] = {0};5 int num[6] = { 0};6 for (int i = 1; i <= 5; ++i)7 cin >>num[i];8 int temp = 0;9 bubble_sort(num, 5);10

11 int num1[6] = { 0};12 float arr[6] = { 0};13 float min = 0;14 for (int a5 = 0; a5 <= num[5];++a5)15 for (int a4 = a5; a4 <= num[4];++a4)16 for (int a3 = a4; a3 <= num[3]; ++a3)17 for (int a2 = a3; a2 <= num[2]; ++a2)18 for (int a1 = a2; a1 <= num[1]; ++a1){19 if (a5 > 0){20 num1[5] = a5 - 1;21 num1[4] = a4 - 1;22 num1[3] = a3 - 1;23 num1[2] = a2 - 1;24 num1[1] = a1 - 1;25 bubble_sort(num1, 5);26 arr[5] = 8 * discount[5] + price[num1[1]][num1[2]][num1[3]][num1[4]][num1[5]];27 }28 if (a4 > 0){29 num1[5] =a5;30 num1[4] = a4 - 1;31 num1[3] = a3 - 1;32 num1[2] = a2 - 1;33 num1[1] = a1 - 1;34 bubble_sort(num1, 5);35 arr[4] = 8 * discount[4] + price[num1[1]][num1[2]][num1[3]][num1[4]][num1[5]];36 }37 if (a3 > 0){38 num1[5] =a5;39 num1[4] =a4;40 num1[3] = a3 - 1;41 num1[2] = a2 - 1;42 num1[1] = a1 - 1;43 bubble_sort(num1, 5);44 arr[3] = 8 * discount[3] + price[num1[1]][num1[2]][num1[3]][num1[4]][num1[5]];45 }46 if (a2 > 0){47 num1[5] =a5;48 num1[4] =a4;49 num1[3] =a3;50 num1[2] = a2 - 1;51 num1[1] = a1 - 1;52 bubble_sort(num1, 5);53 arr[2] = 8 * discount[2] + price[num1[1]][num1[2]][num1[3]][num1[4]][num1[5]];54 }55 if (a1 > 0){56 num1[5] =a5;57 num1[4] =a4;58 num1[3] =a3;59 num1[2] =a2;60 num1[1] = a1 - 1;61 bubble_sort(num1, 5);62 arr[1] = 8 * discount[1] + price[num1[1]][num1[2]][num1[3]][num1[4]][num1[5]];63 }64 min = arr[1];65 for (int k = 1; k <= 5;++k)66 if ((arr[k] < min&&arr[k]>0)||min==0)min =arr[k];67 price[a1][a2][a3][a4][a5] =min;68 }69 cout << price[num[1]][num[2]][num[3]][num[4]][num[5]] <

其中bubble_sort是一个基本的冒泡排序算法,由于问题规模有限,我就写了个最简单的冒泡排序,由于比较简单所以这里不再提供。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
买书问题 dp实现 题目:买书 有一书店引进了一套书,共有3卷,每卷书定价是60元,书店为了搞促销,推出一个活动,活动如下: 如果单独购买其中一卷,那么可以打9.5折。 如果同时购买两卷不同的,那么可以打9折。 如果同时购买三卷不同的,那么可以打8.5折。 如果小明希望购买第1卷x本,第2卷y本,第3卷z本,那么至少需要多少钱呢?(x、y、z为三个已知整数)。 1、过程为一次一次的购买,每一次购买也许只买一本(这有三种方案),或者买两本(这也有三种方案), 或者三本一起买(这有一种方案),最后直到买完所有需要的书。 2、最后一步我必然会在7种购买方案中选择一种,因此我要在7种购买方案中选择一个最佳情况。 3、子问题是,我选择了某个方案后,如何使得购买剩余的书能用最少的钱?并且这个选择不会使得剩余的书为负数 。母问题和子问题都是给定三卷书的购买量,求最少需要用的钱,所以有"子问题重叠",问题中三个购买量设置为参数, 分别为i、j、k。 4、的确符合。 5、边界是一次购买就可以买完所有的书,处理方式请读者自己考虑。 6、每次选择最多有7种方案,并且不会同时实施其中多种,因此方案的选择互不影响,所以有"子问题独立"。 7、我可以用minMoney[i][j][k]来保存购买第1卷i本,第2卷j本,第3卷k本时所需的最少金钱。 8、共有x * y * z个问题,每个问题面对7种选择,时间为:O( x * y * z * 7) = O( x * y* z )。 9、用函数MinMoney(i,j,k)来表示购买第1卷i本,第2卷j本,第3卷k本时所需的最少金钱,那么有: MinMoney(i,j,k)=min(s1,s2,s3,s4,s5,s6,s7),其中s1,s2,s3,s4,s5,s6,s7分别为对应的7种方案使用的最少金钱: s1 = 60 * 0.95 + MinMoney(i-1,j,k) s2 = 60 * 0.95 + MinMoney(i,j-1,k) s3 = 60 * 0.95 + MinMoney(i,j,k-1) s4 = (60 + 60) * 0.9 + MinMoney(i-1,j-1,k) s5 = (60 + 60) * 0.9 + MinMoney(i-1,j,k-1) s6 = (60 + 60) * 0.9 + MinMoney(i-1,j,k-1) s7 = (60 + 60 + 60) * 0.85 + MinMoney(i-1,j-1,k-1)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值