1 条题解
-
0
思路
这道题是递归的入门练习。观察题目规则,会发现"数管子根数"这件事有天然的递归结构:
- 一根管子要么不能再剪(奇数,或第一段长度算出来是 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 不会溢出)。
- 1
信息
- ID
- 15
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 2
- 标签
- 递交数
- 5
- 已通过
- 1
- 上传者
吉公网安备22010402001496号