编程之美之买书问题

拿到这个问题,我的第一反应是用贪心算法,优先满足不同种类多的,这样打的折扣比价多。但是,看了书中的分析发现,*

我们设定的贪心策略实际上是有问题的, ie 在买 5 + 3 本的时候会出错。



看到这里,书上说可以利用改进的贪心算法,感觉如果换了相应的折扣数量,可能又会有不同的结果了。因而,没有深入的研究下去。

既然,贪心算法不可行,那就用动态规划呗。

这里的动态规划思路很简单不过写起来有些复杂。我们这里用到了5维数组, 光是init 就写了好多。 其实我在写的时候,就在想有什么简单一点的方法可以方便的帮我把这一大堆数据初始化, 不过想了好久没能想到

<-_->!!

ps: 因为我们在写这个动态规划方法的时候,还没有看书中相应的动态规划部分的介绍。所以,我们的方法与书中是有些出入的,书中用的是 买书时候的“最小表示方法”, 按照买书的数量 保证 Y1 >= Y2 >= Y3 >= Y4 >= Y5。 我们这里没有这样的假定, 直接按照 i 对应 第 i 卷 书的数量。第 1 次用到 5 维数组,各种不舒服斯基 。。。。。。

为了方便,我们一如既往的使用了全局数组, 免去了数组传递时候的各种闹心事。 好吧,我只是太懒了 !!《-_-》!!

源代码如下:

// ================【买书】=================
// @ author         :       zhyh2010
// @ date           :       20150612
// @ version        :       1.1
// @ description    :       动态规划 考虑实际 各个种类的书的本数
// ===============【end 买书】=================

#include <stdlib.h>
#include <stdio.h>

#define NUM 10
#define DIMEMSION 5
#define UNINITAL 0
float g_discount[NUM + 1][NUM + 1][NUM + 1][NUM + 1][NUM + 1] = { UNINITAL };

#define MYPOS(x) (x < 0 ? 0 : x - 1)

void init()
{
    g_discount[1][0][0][0][0] = 0;
    g_discount[0][1][0][0][0] = 0;
    g_discount[0][0][1][0][0] = 0;
    g_discount[0][0][0][1][0] = 0;
    g_discount[0][0][0][0][1] = 0;

    g_discount[1][1][0][0][0] = 0.1;
    g_discount[1][0][1][0][0] = 0.1;
    g_discount[1][0][0][1][0] = 0.1;
    g_discount[1][0][0][0][1] = 0.1;
    g_discount[0][1][1][0][0] = 0.1;
    g_discount[0][1][0][1][0] = 0.1;
    g_discount[0][1][0][0][1] = 0.1;
    g_discount[0][0][1][1][0] = 0.1;
    g_discount[0][0][1][0][1] = 0.1;
    g_discount[0][0][0][1][1] = 0.1;

    g_discount[1][1][1][0][0] = 0.3;
    g_discount[1][1][0][1][0] = 0.3;
    g_discount[1][1][0][0][1] = 0.3;
    g_discount[1][0][1][1][0] = 0.3;
    g_discount[1][0][1][0][1] = 0.3;
    g_discount[1][0][0][1][1] = 0.3;
    g_discount[0][1][1][1][0] = 0.3;
    g_discount[0][1][1][0][1] = 0.3;
    g_discount[0][1][0][1][1] = 0.3;
    g_discount[0][0][1][1][1] = 0.3;

    g_discount[1][1][1][1][0] = 0.8;
    g_discount[1][1][1][0][1] = 0.8;
    g_discount[1][1][0][1][1] = 0.8;
    g_discount[1][0][1][1][1] = 0.8;
    g_discount[0][1][1][1][1] = 0.8;

    g_discount[1][1][1][1][1] = 1.25;
}

// 取6个数中的最大值
float mymax_f(float a, float b, float c, float d, float e, float f)
{
    float tmp_max = a;
    tmp_max = tmp_max > b ? tmp_max : b;
    tmp_max = tmp_max > c ? tmp_max : c;
    tmp_max = tmp_max > d ? tmp_max : d;
    tmp_max = tmp_max > e ? tmp_max : e;
    tmp_max = tmp_max > f ? tmp_max : f;

    return tmp_max;
}

// 根据之前数据 推到 当前 最大折扣
float mymax(int i, int j, int k, int l, int m)
{
    float max5 = UNINITAL;
    float max4 = UNINITAL;
    float max3 = UNINITAL;
    float max2 = UNINITAL;
    float max1 = UNINITAL;
    float max0 = UNINITAL;

    int cond = (i == 0) + (j == 0) + (k == 0) + (l == 0) + (m == 0);
    switch (cond)
    {
    case 0:
        max5 = g_discount[i - 1][j - 1][k - 1][l - 1][m - 1] + g_discount[1][1][1][1][1];
    case 1:
        max4 = g_discount[MYPOS(i - 1)][MYPOS(j - 1)][MYPOS(k - 1)][MYPOS(l - 1)][MYPOS(m - 1)] + g_discount[0][1][1][1][1];
    case 2:
        max3 = g_discount[MYPOS(i - 1)][MYPOS(j - 1)][MYPOS(k - 1)][MYPOS(l - 1)][MYPOS(m - 1)] + g_discount[0][0][1][1][1];
    case 3:
        max2 = g_discount[MYPOS(i - 1)][MYPOS(j - 1)][MYPOS(k - 1)][MYPOS(l - 1)][MYPOS(m - 1)] + g_discount[0][0][0][1][1];
    case 4:
        max1 = g_discount[MYPOS(i - 1)][MYPOS(j - 1)][MYPOS(k - 1)][MYPOS(l - 1)][MYPOS(m - 1)] + g_discount[0][0][0][0][1];
    case 5:
        max0 = g_discount[MYPOS(i - 1)][MYPOS(j - 1)][MYPOS(k - 1)][MYPOS(l - 1)][MYPOS(m - 1)] + g_discount[0][0][0][0][0];
        break;
    default:
        break;
    }

    return mymax_f(max0, max1, max2, max3, max4, max5);
}

float computeDiscount(int x1, int x2, int x3, int x4, int x5)
{
    if (UNINITAL != g_discount[x1][x2][x3][x4][x5])
        return g_discount[x1][x2][x3][x4][x5];

    for (int i = 0; i != x1 + 1; i++)
    {
        for (int j = 0; j != x2 + 1; j++)
        {
            for (int k = 0; k != x3 + 1; k++)
            {
                for (int l = 0; l != x4 + 1; l++)
                {
                    for (int m = 0; m != x5 + 1; m++)
                    {
                        g_discount[i][j][k][l][m] = mymax(i, j, k, l, m);
//                      printf("x1 = %d, x2 = %d, x3 = %d, x4 = %d, x5 = %d本书的最低折扣为:\t%.2f\n",
//                          i, j, k, l, m, g_discount[i][j][k][l][m]);
                    }
                }
            }
        }
    }

    return g_discount[x1][x2][x3][x4][x5];
}

void main()
{
    init();
    int x1 = 3;
    int x2 = 2;
    int x3 = 1;
    int x4 = 1;
    int x5 = 1;
    computeDiscount(3, 2, 1, 1, 1);
    printf("买 x1 = %d, x2 = %d, x3 = %d, x4 = %d, x5 = %d本书的最低折扣为:\t%.2f\t\t价格为:%.2f\n",
        x1, x2, x3, x4, x5, g_discount[x1][x2][x3][x4][x5],
        (x1 + x2 + x3 + x4 + x5 -g_discount[x1][x2][x3][x4][x5]) * 8);
}
时间: 2024-09-29 04:49:52

编程之美之买书问题的相关文章

编程之美之买票找零

题目:假设有2N个人在排队买票,其中有N个人手持50元的钞票,另外有N个人手持100元的钞票,假设开始售票时,售票处没有零钱,问这2N个人有多少种排队方式,不至使售票处出现找不开钱的局面? 分析:队伍的序号标为0,1,...,2n-1,并把50元看作左括号,100元看作右括号,合法序列即括号能完成配对的序列.对于一个合法的序列,第0个一定是左括号,它必然与某个右括号配对,记其位置为k.那么从1到k-1.k+1到2n-1也分别是两个合法序列.那么,k必然是奇数(1到k-1一共有偶数个),设k=2i

求二进制数中1的个数(编程之美)

求二进制数中1的个数 继京东618店庆时买的<编程之美>这本书,翻了翻,发现里面的题还是挺有意思的,看起来我们觉得很简单的题目,解法却有很多很多种,真是一个比一个巧妙,于是,决定记录一下. 书中的题目如下 对于一个字节(8bit)的无符号数,求其二进制表示中"1"的个数,要求算法的执行效率尽可能高. 就像书中给我们说的一样,我们一般人可能想到的解决方法如下 int countOne(int n){ int count=0; while(n){ if(n%2==1){ cou

《编程之美》

自己也是才听老师的介绍,才从网上下载下<编程之美>这本书来阅读. 浏览其目录,发现这样的一本书正时我这个阶段所最需要的,现在大二,已经有了一定的基础,所以再看以前那些基础教程总觉得,太简单了.但是看太难的东西,又有好些知识没有学过,不理解.所以想<编程之美>这样一本,用到的知识比较基础,但是解题思路很新颖,可以开拓我们的视野,同时书中列出了源代码,只要自己愿意学习,可以迅速仿照例子做出程序,对于树立编程人员的自信心有很大帮助,同时短小的程序,可以迅速做出来,可以当做空闲时间的一种休

编程之美-小飞的电梯调度算法另一种解

放暑假了,在家闲着也是闲着,翻一翻去年买的<编程之美>这本书,有一些收获.昨天看到小飞的电梯调度算法这个问题,思考一番,得到了和书中给出的标准答案不一样的解决方法. 一.问题描述: 亚洲微软研究院所在的希格玛大厦一共有6部电梯.在高峰时间,每层都有人上下,电梯在每层都停.实习生小飞常常会被每层都停的电梯弄得很不耐烦,于是他提出了这样一个办法:由于楼层并不算太高,那么在繁忙的上下班时间,每次电梯从一层往上走时,我们只允许电梯停在其中的某一层.所有乘客从一楼上电梯,到达某层后,电梯停下来,所有乘客

《编程之美》阅读分享

我阅读的课外书籍是<编程之美>,<编程之美>是一本很好的书,作者试图从书中各种有趣的问题出发,引导读者发现问题,分析问题,解决问题,寻找更优的解法.在阅读过程中,加深了我对代码的认识,充分享受到了学习和编程的乐趣.以下是我在学习过程中遇到的问题与探索: 1.在买书问题中,采取什么样的贪心算法最优? 答:本次选择的书的数量不应该小于下一次可选择的书的最大数量: 每一次选择之前都应该查表,选择其中使得近两次折扣数最大的那个作为本次选择. 2.当数据量很大时,有很多无序的数,从中找出最大

编程之美-1的个数

1的数目 题目:给定一个十进制正整数N,写下从1开始,到N的所有整数,然后数一下其中出现所有"1"的个数. 例如: N=2,写下1~2.这样只出现了1个"1". N=12,我们会写下1,2,3,4,5,6,7,8,9,10,11,12,这样,1的个数是5. 问题是: 1.写一个函数F(N),返回1到N之间出现的"1"的个数,比如F(12)=5; 2.满足条件"F(N)=N"的最大的N是多少?   我们就先来看看问题1的解法吧:

编程之美-分层遍历二叉树

问题:给定一个二叉树,要求按分层遍历该二叉树,即从上到下按层次访问该二叉树(每一层将单独输出一行),每一层要求访问的顺序为从左到右,并将节点依次编号.那么分层遍历如图的二叉树,正确的输出应该为: <span style="font-size:14px;">1 2 3 4 5 6 7 8</span> 书中还给出了问题2:打印二叉树中的某层次的节点(从左到右),其中根结点为第0层,成功返回true,失败返回false 分析与解法 关于二叉树的问题,由于其本身固有的

读书问题之《编程之美》 -----12061161 赵梓皓

我阅读的书是<编程之美> 刚开始的时候阅读序,就觉得控制cpu利用率这个问题很好玩,所以重点看了这部分和解决办法,问题也都大部分是这部分的.那么问题就来了(挖掘机技术xxx?中国山东找蓝翔) 咳咳,问题在下面: 1.关于问题的提出.(也是一点点建议) 本书的主要内容是告诉读者如何思考问题和解决问题.但是提出问题也是很重要的,正如爱因斯坦所说“提出一个问题往往比解决一个问题更重要”,很多面试题(比如井盖为啥是圆的)我觉得正常人很少会想到.所以,这个问题是怎么想出来的...我很好奇.也希望作者能够

【编程之美】目录

第1章  游戏之乐——游戏中碰到的题目 1.1 让CPU占用率听你的指挥 1.2 中国象棋将帅问题 1.3 一摞烙饼的排序 1.4 买书问题 第2章  数字之魅——数字中的技巧 2.1 求二进制中1的个数 2.2 不要被阶乘吓倒 2.3 寻找发帖"水王" 2.4 1的数目 2.5 寻找最大的K个数 2.6 精确表达浮点数 2.7 最大公约数问题 2.8 找符合条件的整数 2.9 斐波那契(Fibonacci)数列 2.10 寻找数组中的最大值和最小值 2.11 寻找最近点对 2.12