1 条题解

  • 0
    @ 2026-8-18 12:06:38

    思路

    这道题是递归的入门练习。观察题目规则,会发现"数管子根数"这件事有天然的递归结构:

    • 一根管子要么不能再剪(奇数,或第一段长度算出来是 0),它自己就是 1 根,答案就是 1;
    • 要么可以剪成两根 a 和 b——那么它的答案 = a 的答案 + b 的答案。

    写成数学形式(设 cut(x) 表示长度 x 的管子最终剩几根):

    cut(x) = 1                          当 x 是奇数
    cut(x) = 1                          当 a = ⌊3x/7⌋ = 0
    cut(x) = cut(a) + cut(b)            其他情况,a = ⌊3x/7⌋,b = x - a
    

    这就是代码里 cut 函数的三个分支。递归的妙处在于:我们不用管剪多少层、怎么安排顺序,每一根管子"问自己"两个问题就够了——能不能剪?能剪就把问题丢给两根小管子。

    关于向下取整:C 里整数除法 n * 3 / 7 自动向下取整,和 ⌊3n/7⌋ 完全一致,不用额外处理。

    关于什么时候 a = 0:当 x 是偶数且 3x < 7,即 x = 2 时(3×2/7 = 0),此时 b = 2,若不拦截会无限递归下去!这就是第二个 return 1 存在的意义。

    代码(填空版答案)

    #include <stdio.h>
    
    int cut(int n) {
        if (n % 2 == 1) {
            return 1;              // 奇数:不能再剪,算 1 根
        }
        if (n * 3 / 7 == 0) {
            return 1;              // 第一段长度为 0:不能再剪,算 1 根
        }
        return cut(n * 3 / 7) + cut(n - n * 3 / 7);
        //                        ↑ 第二段 b = x - a
    }
    
    int main() {
        int n;
        scanf("%d", &n);
        printf("%d\n", cut(n));
        return 0;
    }
    

    用样例走一遍

    n = 8:

    • 8 是偶数,a = 8×3/7 = 24/7 = 3,b = 8 − 3 = 5;
    • cut(3):3 是奇数 → 1;
    • cut(5):5 是奇数 → 1;
    • 总数 = 1 + 1 = 2。✓

    再看一个稍复杂的 n = 14:

    • a = 42/7 = 6,b = 8;
    • cut(6):a = 18/7 = 2,b = 4 → cut(2)(a = 6/7 = 0,返回 1)+ cut(4)(a = 12/7 = 1 奇数返回 1,b = 3 返回 1,共 2)= 3;
    • cut(8) = 2;
    • 总数 = 3 + 2 = 5。

    易错点

    • 第三空容易写成 cut(n - 3 * n / 7) 之外的奇怪形式。注意 a 已经是 n * 3 / 7,b 直接用 n - n * 3 / 7。虽然表达式重复算了一遍,但结果一致;也可以先存变量 int a = n * 3 / 7; 再写 cut(a) + cut(n - a),更清晰。
    • 必须先判 a = 0 再递归,否则 n = 2 时会变成 cut(0) + cut(2),无限递归导致程序崩溃(栈溢出)。
    • 奇数分支和 a = 0 分支都是 return 1,两处别漏。
    • 先乘后除:写 n / 7 * 3 会因为提前取整而算错,一定要 n * 3 / 7(n ≤ 1000,乘 3 不会溢出)。

    信息

    ID
    15
    时间
    1000ms
    内存
    256MiB
    难度
    2
    标签
    递交数
    5
    已通过
    1
    上传者