Skip to content

E01003: Hangover

math, http://cs101.openjudge.cn/pctbook/E01003/

How far can you make a stack of cards overhang a table? If you have one card, you can create a maximum overhang of half a card length. (We're assuming that the cards must be perpendicular to the table.) With two cards you can make the top card overhang the bottom one by half a card length, and the bottom one overhang the table by a third of a card length, for a total maximum overhang of 1/2 + 1/3 = 5/6 card lengths. In general you can make n cards overhang by 1/2 +1/3 + 1/4 + ... + 1/(n + 1) card lengths, where the top card overhangs the second by 1/2, the second overhangs tha third by 1/3, the third overhangs the fourth by 1/4, etc., and the bottom card overhangs the table by 1/(n + 1). This is illustrated in the figure below.

img

输入

The input consists of one or more test cases, followed by a line containing the number 0.00 that signals the end of the input. Each test case is a single line containing a positive floating-point number c whose value is at least 0.01 and at most 5.20; c will contain exactly three digits.

输出

For each test case, output the minimum number of cards necessary to achieve an overhang of at least c card lengths. Use the exact output format shown in the examples.

样例输入

1.00
3.71
0.04
5.19
0.00

样例输出

3 card(s)
61 card(s)
1 card(s)
273 card(s)

来源

Mid-Central USA 2001

这个问题要求我们找到最少的卡片数,使得它们的叠加悬空距离至少为给定的 c 值。

思路分析

每增加一张卡片,叠加的总过hang值是一个调和数列的部分和:

  • 第 1 张卡片过hang 1/2 长度。
  • 第 2 张卡片过hang 1/3 长度。
  • 第 3 张卡片过hang 1/4 长度。
  • 依此类推。

所以,当卡片数量为 n 时,叠加的总过hang值为:

Hn=1/2+1/3+1/4+⋯+1/n+1

我们需要找到最小的 n,使得:

Hn ≥ c

这就变成了一个计算调和数列部分和的问题。

cpp
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    double c;
    while (cin >> c) {
        if (c == 0.00) {
            break;
        }
        
        double overhang = 0.0;
        int cards = 0;

        // 增加卡片,直到总过hang值大于等于c
        while (overhang < c) {
            cards++;
            overhang += 1.0 / (cards + 1);  // 每张卡片的过hang值
        }

        // 输出结果,卡片数量
        cout << cards << " card(s)" << endl;
    }

    return 0;
}

<iomanip> 是 C++ 标准库中的一个头文件,主要用于处理输入输出的格式化。它提供了一些控制输入输出格式的工具,例如设置数字的精度、宽度、对齐方式等。

常见的 iomanip 功能:

  1. 设置输出的精度(setprecisionsetprecision 用来指定浮点数输出的精度,即输出小数点后保留的位数。

    cpp
    #include <iostream>
    #include <iomanip>
    using namespace std;
                                                                                                                                                    
    int main() {
        double pi = 3.14159265358979;
        cout << setprecision(5) << pi << endl; // 输出 3.1416
        return 0;
    }

    这个例子中,setprecision(5) 设置了输出精度为 5 位数字。

  2. 固定小数点输出(fixed: 默认情况下,C++ 会根据数字的大小自动决定浮点数是以科学计数法(例如 1.23e+4)还是普通的十进制形式输出。如果你希望强制浮点数以小数点形式输出,可以使用 fixed

    cpp
    #include <iostream>
    #include <iomanip>
    using namespace std;
                                                                                                                                                    
    int main() {
        double pi = 3.14159265358979;
        cout << fixed << setprecision(4) << pi << endl; // 输出 3.1416
        return 0;
    }

    这段代码会强制 pi 以小数点形式输出,保留 4 位小数。

  3. 设置输出宽度(setwsetw 用来设置输出字段的宽度。如果输出的数据宽度小于 setw 设置的宽度,C++ 会自动填充空格来补齐。

    cpp
    #include <iostream>
    #include <iomanip>
    using namespace std;
                                                                                                                                                    
    int main() {
        int x = 42;
        cout << setw(5) << x << endl;  // 输出 "   42"(宽度为5)
        return 0;
    }
  4. 对齐设置(left, right, internal: 通过 left, right, 和 internal 来控制输出对齐方式:

    • left:左对齐
    • right:右对齐(默认)
    • internal:将符号位(正负号)对齐到输出字段的内部(即数字右侧,符号前)
    cpp
    #include <iostream>
    #include <iomanip>
    using namespace std;
                                                                                                                                                    
    int main() {
        cout << left << setw(10) << "Hello" << endl;  // 输出 "Hello     "
        cout << right << setw(10) << "Hello" << endl; // 输出 "     Hello"
        return 0;
    }
  5. 填充字符(setfillsetfill 用于设置输出时填充字符。如果字段宽度不足,输出会使用该字符来填充。

    cpp
    #include <iostream>
    #include <iomanip>
    using namespace std;
                                                                                                                                                    
    int main() {
        cout << setfill('*') << setw(10) << 42 << endl;  // 输出 "******42"
        return 0;
    }

常见的 iomanip 常量:

  • fixed:强制以小数点形式输出浮点数。
  • scientific:强制以科学计数法输出浮点数。
  • setprecision(n):设置浮点数输出的精度,保留 n 位小数。
  • setw(n):设置输出的宽度,输出内容小于 n 时会自动填充空格。
  • setfill(ch):设置填充字符,输出内容小于指定宽度时会用该字符填充。

示例代码:

cpp
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    double pi = 3.14159265358979;
    int number = 42;

    // 设置精度为 3 位小数
    cout << fixed << setprecision(3) << pi << endl;  // 输出 3.142
    
    // 设置输出宽度为 10,使用填充字符 '*'
    cout << setfill('*') << setw(10) << number << endl;  // 输出 "******42"
    
    // 设置对齐方式为右对齐
    cout << right << setw(10) << number << endl;  // 输出 "       42"

    return 0;
}

总结:

<iomanip> 使得你可以灵活地控制 C++ 输出格式,常用的有设置浮点数精度、输出宽度、对齐方式、填充字符等功能。