《编程之美》1.4 买书问题 贪心策略

这里讨论的是贪心策略!

书中1.4首先给出了一个动态规划版本,我第一次看编程之美的时候,自己一下子也想到了动态规划版本,就没往后看了。书中讲到的动态规划版本此处不再重述。

今天重新看了下才知道后面的贪心才是精华。

(1)按照正常的思路,我们有了以下贪心策略:购买Y5本5卷(5卷是总数,不是指第5卷),购买Y4-Y5本4卷,购买Y3-Y4本3卷,购买Y3-Y4本3卷,购买Y2-Y3本2卷,购买Y1-Y2本1卷

(2)这样,按照上述策略,我们可以得到总代价为:

        total_cost = Y5 * 5 * 8 * (1 - 25%) +

                           (Y4 - Y5) * 4 * 8* (1 - 20%) +

                           (Y3 - Y4) * 3 * 8* (1 - 10%) +

                           (Y2 - Y3) * 2 * 8* (1 - 5%) + 

                           (Y1 - Y2) * 1 * 8* 100%

                         = 8     * (Y1 - Y2) + 

                            15.2 * (Y2 - Y3)+

                            21.6 * (Y3 - Y4)+ 

                            25.6 * (Y4 - Y5)+

                            30   * Y5       --------------------   式A

(3)观察式A,我们这个贪心策略一定是最优的吗?如果不是该怎么调整?(需要调整)

        观察式A,我们可以把1个3卷和1个5卷合并成2个4卷,合并之前的所附付金额是 P1 = 21.6 + 30 = 51.6,

        和并之后的金额是P2 = 2 × 25.6 = 51.2。 P2 < P1,所以这个合并调整可以取得更优的结果。其他的合并调整策略,如1个1卷和

        1个3卷合成2个2卷,都会使所付金额偏大,因此不能使结果更优。所以调整的策略只有1个3卷和1个5卷合并调整成2个4卷。

(4)通过上述分析,我们得到最终贪心策略:

        购买Y5 - K 本5卷,Y4 - Y5 + 2K本4卷,Y3 - Y4 - K本3卷, Y2 - Y3本2卷, Y1 - Y2本1卷, K = min(Y3 - Y4, Y5)

如:我们要买的书用(7,6,3,2,1)表示。

Y1=7,Y2=6,Y3=3,Y4=2,Y5=1;

K=min(Y3-Y4,Y5)=1;

Y1-Y2=1;Y2-Y3=3;Y3-Y4-K=0; Y4 - Y5 + 2K=3; Y5– K=0。

即购买0本5卷,3本4卷,0本3卷,3本2卷,1本1卷。

 

由此可得解法如下:

代码:

const double BuyBook::UNIT_PRICE = 8;

const double BuyBook::DISCOUNTS[5] = {1,0.95, 0.9, 0.8, 0.75};

static const int BOOK_KINDS = 5;

double BuyBook::SearchCheapest(int* books)

{

    Sort(books);//从大到小排列

    int g[5];

    g[0] = books[0] - books[1];

    g[1] = books[1] - books[2];

    g[2] = books[2] - books[3];

    g[3] = books[3] - books[4];

    g[4] = books[4];

    int t = min(g[2], g[4]);

    if (t > 0)//策略的调整

    {

        g[2] -= t;

        g[4] -= t;

        g[3] += 2 * t;

    }

    double sum = 0;

    for (int i = 0; i < BOOK_KINDS;++i)

    {

        sum += g[i] *(i+1) * UNIT_PRICE * DISCOUNTS[i];

    }

    return sum;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值