一、先把题目变成一个“小故事”🏰
小双正在研究一种神奇的数字数列。
他发现:
如果连续的两个数字是直角三角形的两条直角边,那么下一个数字就可以当作斜边。
还记得勾股定理吗?
如果一个直角三角形:
/| / | / | b / | /____| a那么:
所以:
二、数列规则到底是什么?
题目规定:
第1项 = a 第2项 = b 第3项 = √(第1项² + 第2项²) 第4项 = √(第2项² + 第3项²) 第5项 = √(第3项² + 第4项²)是不是很像:
🧙♂️“前两个数字合体,召唤出下一个数字!”
三、先看题目的样例
输入:
3.0 4.0 10.0意思是:
第一项 = 3 第二项 = 4 上限 = 10题目要求:
第几项开始超过 10?
题目给出的数列过程是:3、4、5、约6.403、约8.124、约10.344……,因此答案是第6项。
我们亲自算一遍。
四、第一关:第3项怎么算?
现在:
第1项 = 3 第2项 = 4根据规则:
第3项=
也就是:
= 5
所以:
3 4 5五、第二关:第4项怎么算?
现在前两个数字变成:
4 5所以:
第4项 =
大约:
6.403于是:
3 4 5 6.403六、继续!
第5项:
大约:
8.124第6项:
大约:
10.344终于:
10.344 > 10🎉 找到了!
所以答案:
6这正是题目的样例输出。
七、现在问题来了:C++ 怎么写?
我们刚才是人脑在算:
3 → 4 → 5 → 6.403 → 8.124 → 10.344但是计算机不会自己猜。
我们必须告诉它:
“只要当前数字还没有超过上限,就继续召唤下一个数字!”
这时候就要请出我们的老朋友:
⭐while循环
八、先设计变量
我们需要三个主要变量:
double a, b, U;分别表示:
a → 当前的前一个数字 b → 当前的最后一个数字 U → 上限例如开始:
a = 3 b = 4 U = 10九、为什么只需要两个数字?
这是这道题非常值得孩子理解的地方。
我们原来的数列好像很长:
3 4 5 6.403 8.124 10.344 ……是不是需要把所有数字都存下来?
不需要!
因为计算下一个数字的时候,我们只需要:
前一个 + 最后一个例如:
3 4 ↓ 5得到 5 后:
4 5 ↓ 6.403再得到:
5 6.403 ↓ 8.124所以我们只需要两个“数字盒子”:
┌──────┐ │ a │ ├──────┤ │ 3 │ └──────┘ ┌──────┐ │ b │ ├──────┤ │ 4 │ └──────┘每次产生新数字以后:
旧的 b 变成新的 a,新数字变成新的 b。
这就是整个程序最关键的“换位魔法”!✨
十、核心公式怎么写?
数学公式:
C++:
double t = sqrt(a * a + b * b);这里:
sqrt()就是:
求平方根
例如:
sqrt(25)得到:
5.0所以:
sqrt(a * a + b * b)就是把勾股定理直接变成 C++。
十一、最关键的“换位魔法”🔄
假设:
a = 3 b = 4先算:
double t = sqrt(a * a + b * b);得到:
t = 5现在我们希望:
a = 4 b = 5所以:
a = b; b = t;变成:
原来: a → 3 b → 4 t → 5 执行 a = b: a → 4 b → 4 t → 5 执行 b = t: a → 4 b → 5 t → 5于是:
a = 4 b = 5下一轮就可以继续算:
十二、但是有一个问题:什么时候停止?
题目问的是:
第几项开始超过 U?
所以我们可以一直检查:
while (b <= U)意思是:
“只要目前的最后一项还没有超过上限,就继续往下算。”
一旦:
b > U就停止!
十三、为什么ans一开始是 1?
这个地方很容易让初学者疑惑。
程序:
int ans = 1;为什么不是:
int ans = 0;因为一开始我们手里已经有:
第1项 a 第2项 b我们要计算的是:
到底第几项超过上限。
所以程序用ans来记录当前已经走到第几项。
情况1:第一项已经超过上限
例如:
a = 20 b = 30 U = 10第1项:
20 > 10答案就是:
1所以:
int ans = 1;然后:
if (a <= U) ans++;如果第一项没有超过上限,才继续把答案位置往后移动。
十四、把整个程序“翻译成人话”
参考程序是:
#include <iostream> #include <cmath> using namespace std; int main() { double a, b, U; cin >> a >> b >> U; int ans = 1; if (a <= U) ans++; while (b <= U) { ans++; double t = sqrt(a * a + b * b); a = b; b = t; } cout << ans << endl; return 0; }这是题目给出的参考程序。
现在我们把它解析一下。
第1步:准备三个盒子
double a, b, U;三个盒子:
a → 前一个数字 b → 当前数字 U → 上限第2步:输入
cin >> a >> b >> U;例如:
3 4 10于是:
a = 3 b = 4 U = 10第3步:准备答案
int ans = 1;从第1项开始数。
第4步:看看第1项是否超过上限
if (a <= U) ans++;因为:
3 <= 10所以:
ans = 2意思是:
“第1项没有超,现在至少要继续看第2项。”
十五、进入while大冒险!🚀
现在:
a = 3 b = 4 U = 10 ans = 2判断:
while (b <= U)也就是:
4 <= 10成立!
继续!
第一次循环
ans = 3计算:
= 5
所以:
t = 5然后:
a = b; b = t;得到:
a = 4 b = 5第二次循环
检查:
5 <= 10成立。
所以:
ans = 4计算:
于是:
a = 5 b = 6.403第三次
6.403 <= 10成立。
所以:
ans = 5计算:
b ≈ 8.124第四次
8.124 <= 10成立。
所以:
ans = 6继续计算:
b ≈ 10.344十六、终于遇到“大门”🚪
现在:
b ≈ 10.344 U = 10检查:
b <= U也就是:
10.344 <= 10❌ 不成立!
所以while停止。
此时:
ans = 6输出:
6十七、给同学们画一张“变量变化表”
| 阶段 | a | b | ans | 动作 |
|---|---|---|---|---|
| 开始 | 3 | 4 | 2 | 两项都还没超过10 |
| 第1次 | 4 | 5 | 3 | 生成5 |
| 第2次 | 5 | 6.403 | 4 | 生成6.403 |
| 第3次 | 6.403 | 8.124 | 5 | 生成8.124 |
| 第4次 | 8.124 | 10.344 | 6 | 生成10.344 |
| 停止 | — | 10.344 | 6 | 超过10 |
这样一看,整个程序就不神秘了。
十八、这道题真正考什么?
千万不要认为这题只是考:
“会不会
sqrt()。”
其实它考了至少5个知识点。
①double
因为数列里面有:
6.403... 8.124... 10.344...有小数,所以不能使用普通的:
int而要使用:
double②sqrt()
sqrt(x)表示:
求 x 的平方根。
需要:
#include <cmath>③while
因为我们不知道需要计算多少次。
可能:
第3项超过也可能:
第10项超过甚至:
第100项超过所以非常适合:
while (...)④ 变量更新
这是本题最重要的编程思想之一:
a = b; b = t;它不是随便写的。
而是在做:
旧的“最后一个” ↓ 变成 新的“前一个” 新计算出来的数字 ↓ 成为 新的“最后一个”⑤ “什么时候停止”
while (b <= U)这是算法思想:
没超过 → 继续
超过了 → 停止
这叫做循环的终止条件。
十九、同学们最容易犯的4个错误 ⚠️
错误1:把a、b一直不更新
如果写成:
while (b <= U) { double t = sqrt(a*a+b*b); }那么:
a、b一直没变化!
程序可能一直算:
3和4 3和4 3和4 3和4 ……💥 死循环!
所以:
a = b; b = t;非常重要。
错误2:使用int
如果:
int a, b;那么小数会被丢掉,可能导致错误。
本题应该使用:
double错误3:把公式写错
正确:
sqrt(a * a + b * b)不是:
sqrt(a * a + b)更不是:
sqrt(a + b) * sqrt(a + b)一定要记住:
a2+b2\boxed{\sqrt{a^2+b^2}}
错误4:不理解ans
ans不是“计算了几次”。
它最终表示:
第几项第一次超过上限。
这两个概念很接近,但不要混淆。
二十、最后把这道题压缩成一个“万能思维模板”🧠
以后遇到这种:
不断根据前面的数据生成新数据,直到满足某个条件
可以想成:
准备初始数据 ↓ 判断有没有结束 ↓ 生成新数据 ↓ 更新旧数据 ↓ 再判断 ↓ …… ↓ 满足结束条件 ↓ 输出答案对应本题就是:
a、b ↓ b有没有超过U? ↓ 没有 ↓ t = √(a²+b²) ↓ a=b b=t ↓ 继续 ↓ b > U ↓ 输出第几项🌟 一句话记住这道题
送给同学们一个非常好记的口诀:
“两个数字合体,开平方根;旧 b 变新 a,新数字变新 b;没超过就继续,超过了就停!”