POJ 3737 UmBasketella & printf占位符%lf和%f & cin/cout取消绑定加速 & cin/cout保留小数位数

POJ 3737 UmBasketella

推导之后发现,体积先增后减,所以我们三分。

#include <stdio.h>

#include <algorithm>
#include <cmath>
#include <iostream>
#include <string>

#define For(i, j, n) for (int i = j; i <= n; ++i)

const double pi = acos(-1.0);
const double eps = 1e-9;

double S;  // 表面积

double r, h;  //	半径和高
double l;	//	母线长

double GetVolume(const double &r) {
    l = (S - r * r) / r;
    h = sqrt(l * l - r * r);
    return pi * r * r * h / 3.0;
}

inline double TernarySearch() {
    double leftBound = 0.0, rightBound = sqrt(S/2);
	double V1, V2, m1, m2;
    while (rightBound - leftBound > eps) {
        double gap = (rightBound - leftBound) / 3.0;
        m1 = leftBound + gap, m2 = rightBound - gap;
        V1 = GetVolume(m1), V2 = GetVolume(m2);
        if (V1 > V2) {
            rightBound = m2;
        } else {
            leftBound = m1;
        }
    }
    r = rightBound;
	return GetVolume(r);
}

int main() {
    while (~scanf("%lf", &S)) {
		S /= pi;
        double ans = TernarySearch();
        printf("%.2f\n%.2f\n%.2f\n", ans, h, r);
    }
    return 0;
}

key points 1. 输出占位符影响正确性

这道题玄学的地方在于,最后输出的时候用%.2lf无法通过,换成%.2f才行,针对此问题,GPT是这样解释的:

这是一个 浮点数输出格式要求的问题。在一些竞赛平台或在线评测系统上(如 POJ),输出格式必须严格符合题目要求,哪怕是小数位数的差异都会导致 Wrong Answer。让我们详细分析为什么 %.2f 可以通过,而 %.2lf 不能。


%.2f vs. %.2lf 区别

1. 格式说明符解释

  • %f 是用于格式化 float/double 类型的输出格式符。
  • printf 中:
    • %f:用于输出 floatdouble 类型的小数。
    • %lf也是用于double,但它的使用与 scanf 更相关。

2. 为什么 %.2lf 导致错误?

  • printf 实际上不区分 %f%lf,在 C 标准中,printf 中使用 %f 即可处理所有 floatdouble 数据。因此,%.2lf 虽然语法上不会出错,但它可能会导致输出与题目严格要求不符

3. 竞赛系统的严格格式检查

  • 有些竞赛平台会严格匹配 输出格式,包括空格、换行符和小数位数的格式
  • 在这个问题中,题目要求两位小数
    • %.2f 输出格式符合这个要求。
    • %.2lf 虽然语法正确,但它可能在底层存储或匹配时与题目要求存在微小差异,导致评测系统判定为 Wrong Answer

正确使用的总结

  • printf 中,只需要使用 %f 即可处理 floatdouble,不必使用 %lf
  • scanf 中,%lf 是必要的,因为它用于区分 doublefloat 输入:
    double x;
    scanf("%lf", &x);  // 必须使用 %lf 来读取 double 类型
    

如何避免类似问题?

  1. 始终使用 %.2f 处理浮点数输出,避免多余的格式化问题。
  2. 确保输出与题目要求完全一致,包括小数位数空格换行符

总结

  • %.2lfprintf 中并不会影响程序的执行,但可能与题目的严格格式检查不符。
  • 使用 %.2f 是更好的选择,因为这是标准的浮点数格式化输出方法,能确保与评测系统的要求一致。

key points 2.cin cout取消绑定加速&指定小数位数

在 C++ 中,std::cout 可以通过一些格式化设置来指定 小数位数,并且通过取消与 C 风格 I/O 的同步来加速输出。下面详细说明这些操作。


1. 使用 std::cout 指定小数位数

方法:std::fixedstd::setprecision

  • std::fixed:指定使用定点表示法(而不是科学计数法)。
  • std::setprecision(n):指定要保留的小数位数。

示例代码:指定两位小数

#include <iostream>
#include <iomanip>  // 需要引入 iomanip 头文件

int main() {
    double value = 3.141592653589793;

    std::cout << std::fixed << std::setprecision(2);
    std::cout << "Value: " << value << std::endl;

    return 0;
}

输出

Value: 3.14

说明:

  • std::fixed:确保输出为 定点小数
  • std::setprecision(2):设置保留 2 位小数
  • 如果没有 std::fixedstd::cout 可能会根据数值大小使用 科学计数法

2. 加速 std::cout:取消绑定同步

默认同步导致性能问题

  • 默认情况下,std::coutC 标准库的 printf 是同步的,以确保两者输出不会交错。这种同步机制会降低输出速度。

如何取消同步来加速输出?

通过以下代码可以取消这种同步,提高 std::cout 的性能:

示例代码:取消同步

#include <iostream>
#include <iomanip>  // 如果需要格式化输出

int main() {
    std::ios::sync_with_stdio(false);  // 取消 C I/O 和 C++ I/O 的同步
    std::cin.tie(0);  // 取消 cin 和 cout 的绑定

    double value = 3.14159;
    std::cout << std::fixed << std::setprecision(2);
    std::cout << "Value: " << value << std::endl;

    return 0;
}

说明:

  1. std::ios::sync_with_stdio(false);

    • 取消 C 和 C++ I/O 的同步,使得 std::cout 输出速度更快。
    • 注意:如果你还使用 printf 或其他 C 风格 I/O 函数,可能会出现输出交错问题。
  2. std::cin.tie(0);

    • 取消 std::cinstd::cout 的绑定。默认情况下,std::cin 每次读取时会自动刷新 std::cout,取消绑定后可以进一步提升性能。

加速效果对比

  • 未取消同步:处理大量数据输出时,std::cout 速度会较慢。
  • 取消同步:速度提升明显,尤其在 算法竞赛或需要快速 I/O 的场合。

总结

  • 指定小数位数:使用 std::fixedstd::setprecision
  • 加速 std::cout 输出
    1. 使用 std::ios::sync_with_stdio(false); 取消 C 和 C++ I/O 的同步。
    2. 使用 std::cin.tie(0); 取消输入输出的绑定。

这些方法在处理大量数据时会显著提升性能,同时格式化输出也会更加灵活。
并且经过尝试,发现这道题用cout来固定位数也是可以通过的。

posted @ 2024-10-20 18:52  Gold_stein  阅读(21)  评论(0编辑  收藏  举报