原始题目

以下代码的输出是什么?

#include <iostream>
using namespace std;
int main() {
    int n = 27;
    while (n != 1) {
        if (n % 2 == 0) n /= 2;
        else n = 3 * n + 1;
        cout << n << " ";
    }
    return 0;
}

答案:打印 111 个数,从 82 一直到 1(末尾带空格,无换行)


这是著名的 3n+1 问题(Collatz 猜想)

  • n 是偶数:n /= 2
  • n 是奇数:n = 3n + 1
  • 循环直到 n 变成 1

Collatz 猜想:任意正整数经过有限步都会回到 1。这个猜想至今无人证明,但计算机已经验证到 \(2^{68}\) 以上的所有数都成立。

序列忽上忽下、最后总会坠回 1,像冰雹在云层中上下翻滚,所以又叫冰雹数

n = 27 是最经典的例子:只需 111 步,中途却冲到 9232 的峰值——27 也是「步数远超比它小的数」的著名反差代表。

轨迹图

蓝点 = 奇数步(3n+1 上升),绿点 = 偶数步(n/2 下降):

3n+1 冰雹序列(n = 27):111 步回到 1 奇数 → 3n+1(上升) 偶数 → n/2(下降) 0 2000 4000 6000 8000 10000 0 20 40 60 80 100 步数(0 = 初始值 27) n 的值 峰值 9232 27

前几个数的手算模拟

27 → 82 → 41 → 124 → 62 → 31 → 94 → 47 → 142 → 71 → 214 ...
  • 27 是奇数:27×3+1 = 82 ← 第一个输出
  • 82 是偶数:82/2 = 41
  • 41 是奇数:41×3+1 = 124
  • 之后一路忽上忽下,第 77 步冲到峰值 9232,再一路跌回 1

三个隐藏考点

  1. 初始的 27 不会打印——coutn 更新之后执行,第一个输出是 82。如果 cout 放在循环开头,才会先打 27。
  2. 无换行:每个数后面是空格,最后也不会输出 endl
  3. 死循环风险:若初值 n = 0(或负数),n != 1 永远为真——0 一直除 2 还是 0,程序永不停止。正整数没问题。

数据规模:27 的全过程峰值只有 9232,int 完全够用;但如果起始数更大,中途可能超过 \(2^{31}\),竞赛中稳妥起见用 long long

考点总结(CSP-J 初赛选择题)

  1. 认出 3n+1 / Collatz / 冰雹数 模型:偶数减半、奇数三倍加一。
  2. 注意 cout 位置决定初始值是否被打印
  3. 循环条件 n != 10 和负数会死循环。
  4. 27 的步数是 111,峰值 9232——选择题若问「大约多少步」「最大值」,可直接选接近的量级。

思考题

n = 27 改成 n = 7,会打印多少个数?

答案 16 个:7 → 22 → 11 → 34 → 17 → 52 → 26 → 13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1,打印的是从 22 到 1 共 16 个数。