PAT-L2月饼,初用贪心算法,巧遇精度问题(两个数相除,类型不一样,容易损失精度),float,double与0的比较,任意两个浮点数的比较。

以前只是听说过贪心算法,今天做题就实际运用了一次。贪心算法一般用于优化问题,即求最大最小
与动态规划可以相互转换(还没开始用动态规划呢,下次学习动态规划)。
总结一下贪心算法的使用步骤:
1.将问题分解 成一个子问题:如本题:可以分解为卖m次月饼。
2.对于每一个子问题,都要求其值达到最优(没有考虑全局最优,只考虑了局部)。如本题:每卖一次月饼,都要使收益最大
3.保证在约束条件下,这里指的就是卖的月饼不能超过需求量
其他复杂的问题也是这个思路。当然也得判断所求问题到底适不适合用贪心算法。简单点就是 问题可以分解为子问题,求解子问题的最优解有助于得到该问题的最优解。这就要求我们要小心使用贪心算法,不要瞎用。不要强行拆为子问题。
下面,看一下这道月饼题目:
月饼是中国人在中秋佳节时吃的一种传统食品,不同地区有许多不同风味的月饼。现给定所有种类月饼的库存量、总售价、以及市场的最大需求量,请你计算可以获得的最大收益是多少。

注意:销售时允许取出一部分库存。样例给出的情形是这样的:假如我们有 3 种月饼,其库存量分别为 18、15、10 万吨,总售价分别为 75、72、45 亿元。如果市场的最大需求量只有 20 万吨,那么我们最大收益策略应该是卖出全部 15 万吨第 2 种月饼、以及 5 万吨第 3 种月饼,获得 72 + 45/2 = 94.5(亿元)。

输入格式:
每个输入包含一个测试用例。每个测试用例先给出一个不超过 1000 的正整数 N 表示月饼的种类数、以及不超过 500(以万吨为单位)的正整数 D 表示市场最大需求量。随后一行给出 N 个正数表示每种月饼的库存量(以万吨为单位);最后一行给出 N 个正数表示每种月饼的总售价(以亿元为单位)。数字间以空格分隔。

输出格式:
对每组测试用例,在一行中输出最大收益,以亿元为单位并精确到小数点后 2 位。

求解思路:对每种月饼的单价排序(注意是单价,题目给的总价)(排序使用的是冒泡排序)
卖m次月饼,每次都选单价最高的卖,注意 不要超过需求量D。
遇到的小问题:

#include<stdio.h>
int main()
{
	double f;
	scanf("%f",&f);
	printf("%0.2f",f);

}

刚开始年少无知,不知道double类型的输入于输出的控制符不一样,于是就这样写了。
看一下运行结果
我输了,太天真了。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200409031805335.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTI5MDM1Mg==,size_16,color_FFFFFF,t_70)

```c
#include<stdio.h>
int main()
{
	double f;
	scanf("%lf",&f);
	printf("%0.2f",f);

其实输入要改为 %lf,以前都不知道,学到了,学到了。
还有一个小问题就是:
我有一个测试点不通过。那就是测试点3
最后终于找到了,是数据类型的问题
其实也就是精度的问题,我把月饼数量之前定义为int。
然后求单价时 用double/int 类型可能会丢失精度。而丢失精度对于要用double类型的单价进行排序时,会产生致命的错误。(0.00000001>0),而一旦丢失了精度,就排序错误了。这样的错误也很难发现,建议做除法时保证 除数和被除数 的类型一致,有小数就定义 为 double。、
这也是排序 的一个很重要的地方 精度问题。还有就是 double a 类型判断是不是为0,
不要写成a == 0;这样写又会发生错误,一般认为sqrt(a) < 这是规定的一个数,一个很小的数如0.0000000001,就可以认为a为0了。
总结一下 测试点 3:数据类型的问题。
除数和被除数 数据类型保持一致
需要对小数比较,排序,(可以作差判断与0比较)判断是不是为0 ,其实都需要规定一个很小的数作为参照。
注意::!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
float ,double 变量与 0的比较:(重点)
float变量与0的比较的if语句该怎么写?
正确的写法是:
float a;
if ((a>=-EPSINON)&&(a<=EPSINON))
EPSINON是定义好的精度。
float和double类型都是有精度限制的,如果直接与0.0比较或者两个变量进行比较大小,都是错误的。
拓展一下:把0.0换为想比较的任何一个浮点数,就可以比较任意两个浮点数的大小了。因此这就要求我们写程序的时候必须 事先定义精度,再比较 。(对于浮点数)
补充:
float 的范围为2^(-128) 到 2^(127)
double的范围为 2^1024到 2^1023
其精度是由 尾数的位数决定的
float指数位为 23bits.
double 为 52bits.
所以float :2^23 = 8388608.七位,绝对能保证的为6位,一般在比较时可以取7位.。
同理 double 的精度为16位,绝对能保证的为15位,比较时可以取16位。
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
附上正确的代码。你们也一定要注意这个问题哦!!,可能这就是你某些测试点过不了的原因。注意除数和被除数的数据类型。

#include<stdio.h>
int N;
#define EN 0.0000000000000001
typedef struct Mooncakes
{
    double Mooncakes_Num;//月饼数量
    double Mooncakes_Tp;//总价
    double mon;//单价
}M;
M cakes[1005];
int start =1;
void Sort(int start,int N)
{
    for (int i=1;i<N;i++)
        for (int j=1;j<=N-i;j++)
        {
            if ((cakes[j].mon<(EN+cakes[j+1].mon))&&(cakes[j].mon<(cakes[j+1].mon-EN)))
            {
                cakes[0] = cakes[j];
                cakes[j] = cakes[j+1];
                cakes[j+1] = cakes[0]; 
            }
        }

}
int main()//贪心算法
{
    int D;
    scanf("%d %d",&N,&D);
    for (int i=1;i<=N;i++)
    {
        scanf("%lf",&cakes[i].Mooncakes_Num);
    }
    for (int i=1;i<=N;i++)
    {
        scanf("%lf",&cakes[i].Mooncakes_Tp);
        cakes[i].mon = cakes[i].Mooncakes_Tp/cakes[i].Mooncakes_Num;
    }
    Sort(start,N);
    double max = 0.0;
    for (int i=1;i<=N;i++)
    {
        if (cakes[i].Mooncakes_Num<=D)
        {
           
               D-= cakes[i].Mooncakes_Num;
               max += cakes[i].Mooncakes_Tp;
        }
        else 
        {
            max +=cakes[i].mon*D;
            break;
        }
    }
    printf("%.2f\n",max);
    return 0;

}
发布了16 篇原创文章 · 获赞 12 · 访问量 1482

猜你喜欢

转载自blog.csdn.net/weixin_45290352/article/details/105401794