写点什么

每日算法刷题 Day1- 隐式转换与精度丢失

作者:timerring
  • 2022 年 9 月 24 日
    山东
  • 本文字数:1819 字

    阅读完需:约 6 分钟

⭐每日算法系列文章旨在精选重点与易错的算法题,总结常见的算法思路与可能出现的错误,与笔者另一系列文章有所区别,并不是以知识点的形式提升算法能力,而是以实战习题的形式理解算法,使用算法。

1.球的体积

给定你一个球体的半径 RR,请你计算球体的体积。


计算球体的公式为


π取 3.14159。

输入格式

输入一个整数 R。

输出格式

输出格式为 VOLUME = X,其中 XX 为球体的体积,结果保留三位小数。

数据范围

1≤R≤2000

输入样例

3
复制代码

输出样例

VOLUME = 113.097
复制代码

代码

#include <iostream>#include <cstdio>using namespace std;int main(){    double a,V;    cin>>a;    V=(4/3.0)*3.14159*a*a*a;    printf("VOLUME = %.3f",V);    return 0;}
复制代码

错题总结

注意:有些语言中 (4/3) 无法得到 1.3333…,建议在公式中使用 (4/3.0)。

2.钞票

在这个问题中,你需要读取一个整数值并将其分解为多张钞票的和,每种面值的钞票可以使用多张,并要求所用的钞票数量尽可能少。


请你输出读取值和钞票清单。


钞票的可能面值有 100,50,20,10,5,2,1。

输入格式

输入一个整数 N。

输出格式

参照输出样例,输出读取数值以及每种面值的钞票的需求数量。

数据范围

0<N<1000000

输入样例:

576
复制代码

输出样例:

5765 nota(s) de R$ 100,001 nota(s) de R$ 50,001 nota(s) de R$ 20,000 nota(s) de R$ 10,001 nota(s) de R$ 5,000 nota(s) de R$ 2,001 nota(s) de R$ 1,00
复制代码

代码

#include <iostream>
using namespace std;
int main(){ int n, a[7] = {100, 50, 20, 10, 5, 2, 1}; cin >> n; printf("%d\n", n); for (int i = 0; i < 7; i ++ ) { printf("%d nota(s) de R$ %d,00\n", n / a[i], a[i]); n %= a[i]; } return 0;}
复制代码

总结

错题总结:之前的做法太过麻烦,可以考虑采用贪心的思想来完成。用余数作为下一次分解的基数。

3.钞票和硬币

读取一个带有两个小数位的浮点数,这代表货币价值。


在此之后,将该值分解为多种钞票与硬币的和,每种面值的钞票和硬币使用数量不限,要求使用的钞票和硬币的数量尽可能少。


钞票的面值是 100,50,20,10,5,2。


硬币的面值是 1,0.50,0.25,0.10,0.05 和 0.01。

输入格式

输入一个浮点数 N。

输出格式

参照输出样例,输出每种面值的钞票和硬币的需求数量。

数据范围

0≤N≤1000000.00

输入样例:

576.73
复制代码

输出样例:

NOTAS:5 nota(s) de R$ 100.001 nota(s) de R$ 50.001 nota(s) de R$ 20.000 nota(s) de R$ 10.001 nota(s) de R$ 5.000 nota(s) de R$ 2.00MOEDAS:1 moeda(s) de R$ 1.001 moeda(s) de R$ 0.500 moeda(s) de R$ 0.252 moeda(s) de R$ 0.100 moeda(s) de R$ 0.053 moeda(s) de R$ 0.01
复制代码

代码

#include <bits/stdc++.h>using namespace std;int main(){    double sum,b[6]={1.00,0.50,0.25,0.10,0.05,0.01};    int a[6]={100,50,20,10,5,2};    scanf("%lf",&sum);    cout<<"NOTAS:"<<endl;    for(int i=0;i<6;i++)    {        printf("%d nota(s) de R$ %d.00\n",(int)(sum/a[i]),a[i]);        sum-=((int)sum/a[i])*a[i];    }    cout<<"MOEDAS:"<<endl;    for(int i=0;i<6;i++)    {    printf("%d moeda(s) de R$ %.2f\n",(int)(sum/b[i]),b[i]);    printf("%.2f\n",sum);    sum-=((int)(sum/b[i]))*b[i];    }
return 0;}
复制代码

错误

第一个测试样例顺利通过,但是第二个测试样例却报了一发 WA。


具体结果如下:


输入


463.01
复制代码


输出


NOTAS:4 nota(s) de R$ 100.001 nota(s) de R$ 50.000 nota(s) de R$ 20.001 nota(s) de R$ 10.000 nota(s) de R$ 5.001 nota(s) de R$ 2.00MOEDAS:1 moeda(s) de R$ 1.001.010 moeda(s) de R$ 0.500.010 moeda(s) de R$ 0.250.010 moeda(s) de R$ 0.100.010 moeda(s) de R$ 0.050.010 moeda(s) de R$ 0.01 //出现问题0.01
复制代码


在最末尾的时候明明剩余 0.01,0.01/0.01=1,但是却输出 0。

总结

你这里的精度丢失如果从底层来考虑的话是因为浮点数的表示所导致的,其实已开始定义的浮点数就是一个近似值,0.01 实际是 0.010000000000012 这样的数,但是如果用减法的话会导致最后我们看到的 n 显示是 0.01 但是他实际是一个近似 0.01 的一个数,但比 0.01 小,因为定义的比所显示的大所以加上 0.00001 就解决了这个问题,这样可以使原来不够除的数够除了


因此我们可以对上面小数的输出做以下修改:


printf("%d nota(s) de R$ %.2f\n",(int)(sum/b[i]+0.00001),b[i]);
复制代码


结果成功 AC。

发布于: 刚刚阅读数: 6
用户头像

timerring

关注

还未添加个人签名 2022.07.14 加入

还未添加个人简介

评论

发布
暂无评论
每日算法刷题Day1-隐式转换与精度丢失_算法题_timerring_InfoQ写作社区