您的位置:首页 > 编程语言

编程之美 - 买书问题

2016-01-07 09:02 337 查看
问题描述:

一套书共 5 卷,单独买每一卷的每一本8元,没有折扣。 如果一次买不同的卷的几本会有相应的折扣,折扣定义如下:

不同的 2本 : 折扣 5%

不同的 3本 : 折扣 10%

不同的 4本 : 折扣 20%

不同的 5本 : 折扣 25%

一份订单中多本书中,不同的组合可能有不同的价格,设计算法计算出最低的价格。

书中的解题思路 1:

主要也考虑的是动态规划的方式,假设 : 买5卷书的本数分别为 X1, X2, X3, X4, X5。 价格为 F(X1, X2, X3, X4, X5)。

规划一下会有下面一些可能:

每卷买一本 + 剩余部分的最小的价格

5*8*(1-25%) + F (X1-1, X2-1, X3-1, X4-1, X5-1)

有4卷买一本 + 剩余部分的最小的价格

(这里假设前X1 至 X4 卷)

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

有3卷买一本 + 剩余部分的最小的价格

(这里假设前X1 至 X3 卷)

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

有2卷买一本 + 剩余部分的最小的价格

(这里假设前X1 至 X2 卷)

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

只买一本 + 剩余部分的最小的价格

(这里假设X1, 没有折扣)

8 + F (X1-1, X2, X3, X4, X5)

最后我们希望得到它们中最小的就好:

min {

5*8*(1-25%) + F (X1-1, X2-1, X3-1, X4-1, X5-1)

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

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

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

8 + F (X1-1, X2, X3, X4, X5)

}

因为每本书价钱一样的,所以买每卷并不重要,重要的是每卷书在订单中的本数。

所以对 X1, X2, X3, X4, X5 排序会使问题变的简单。在上面的几种假设中,例如: 8 + F (X1-1, X2, X3, X4, X5),如果这时 X1卷已经为 0 了,此时X2卷还不为0, 那用X1-1肯定是不对的,应该是X2-1,但如果对每卷的本数都进行一次判断,肯定是非常麻烦的。

假设 Y1, Y2, Y3, Y4, Y5。是对 X1, X2, X3, X4, X5排序后的数字,且 Y1 >= Y2 >= Y3 >= Y4 >= Y5, 而每次函数 F计算的都是排序后的数字,8 + F (Y1-1, Y2, Y3, Y4, Y5) 就具有通用性了。

递归的退出条件

1) 当所有的值都为 0时肯定返回的价格就是 0 了。这是一个递归的条件。

2) 当Y1, Y2, Y3, Y4, Y5 中有一个小于0时,说明当时的方案是个非法的组合,那也就没必要再继续计算了。但此时不能返回 0,需要返回一个自定义的Max值,使当前的组合方式在min计算中失效就好。

程序代码

#include <iostream>

using namespace std;

#define MAX 1000000

void SortY1_Y5(int &nY1, int &nY2, int &nY3, int &nY4, int &nY5)
{
int nTmp = 0, nMax = 0;
int i = 0, j = 0;
int arrData[5] = {nY1, nY2, nY3, nY4, nY5};

for (i = 0; i < 5; i++)
{
nMax = arrData[i];
for (j = i; j < 5; j++)
{
if (arrData[j] > nMax)
{
nTmp = nMax;
nMax = arrData[j];
arrData[j] = nTmp;
}
}
arrData[i] = nMax;
}

nY1 = arrData[0];
nY2 = arrData[1];
nY3 = arrData[2];
nY4 = arrData[3];
nY5 = arrData[4];
}

double minValue(double dVal1, double dVal2, double dVal3, double dVal4, double dVal5, int& nIndex)
{
double dmin = dVal1;
nIndex = 0;

if (dmin > dVal2)
{
nIndex = 1;
dmin = dVal2;
}

if (dmin > dVal3)
{
nIndex = 2;
dmin = dVal3;
}

if (dmin > dVal4)
{
nIndex = 3;
dmin = dVal4;
}

if (dmin > dVal5)
{
nIndex = 4;
dmin = dVal5;
}
return dmin;
}

// Y1 >= Y2 >= Y3 >= Y4 >= Y5
double Calc(int nY1, int nY2, int nY3, int nY4, int nY5)
{
double dMin = 0;
int nIndex = 0;

if ((nY1 == 0) && (nY2 == 0) && (nY3 == 0) && (nY4 == 0) && (nY5 == 0))
return 0;

if ((nY1 - 1 >= 0) || (nY2 - 1 >= 0) || (nY3 - 1 >= 0) || (nY4 - 1 >=  0) || (nY5 - 1 >= 0))
{
SortY1_Y5(nY1, nY2, nY3, nY4, nY5);
dMin = minValue(
(5*8)*(1-0.25) + Calc(nY1-1, nY2-1, nY3-1, nY4-1, nY5-1),
(4*8)*(1-0.20) + Calc(nY1-1, nY2-1, nY3-1, nY4-1,   nY5),
(3*8)*(1-0.10) + Calc(nY1-1, nY2-1, nY3-1,   nY4,   nY5),
(2*8)*(1-0.05) + Calc(nY1-1, nY2-1,   nY3,   nY4,   nY5),
8  + Calc(nY1-1,   nY2,   nY3,   nY4,   nY5), nIndex);
}
else
{
return MAX;
}

switch (nIndex)
{
case 0:
cout << "Min:   " << dMin << "( " <<nY1-1 << ", " << nY2-1 << ", " << nY3-1 << ", " << nY4-1 << ", " << nY5-1 << ", " << ")"<< endl;
break;
case 1:
cout << "Min:   " << dMin << "( " <<nY1-1 << ", " << nY2-1 << ", " << nY3-1 << ", " << nY4-1 << ", " << nY5 << ", " << ")"<< endl;
break;
case 2:
cout << "Min:   " << dMin << "( " <<nY1-1 << ", " << nY2-1 << ", " << nY3-1 << ", " << nY4 << ", " << nY5 << ", " << ")"<< endl;
break;
case 3:
cout << "Min:   " << dMin << "( " <<nY1-1 << ", " << nY2-1 << ", " << nY3 << ", " << nY4 << ", " << nY5 << ", " << ")"<< endl;
break;
case 4:
cout << "Min:   " << dMin << "( " <<nY1-1 << ", " << nY2 << ", " << nY3 << ", " << nY4 << ", " << nY5 << ", " << ")"<< endl;
break;
default:
break;
}

return dMin;
}

void main()
{
double dMoney = 0;
//int test[5] = {1,1,1,1,1};
//int test[5] = {2,2,2,2,2};
//int test[5] = {1,1,0,0,0};
//int test[5] = {2,2,2,1,1};
int test[5] = {3,2,2,1,1};
//int test[5] = {2,1,1,0,0};

dMoney = Calc(test[0], test[1], test[2], test[3], test[4]);

cout << dMoney << endl;

cin >> dMoney;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: