POJ 3737 UmBasketella & printf佔位符%lf和%f & cin/cout取消繫結加速 & cin/cout保留小數位數

Gold_stein發表於2024-10-20

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來固定位數也是可以透過的。

相關文章