一、先把题目变成一个“小故事”小双正在研究一种神奇的数字数列。他发现如果连续的两个数字是直角三角形的两条直角边那么下一个数字就可以当作斜边。还记得勾股定理吗如果一个直角三角形/| / | / | 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。这就是整个程序最关键的“换位魔法”✨十、核心公式怎么写数学公式Cdouble 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十七、给同学们画一张“变量变化表”阶段abans动作开始342两项都还没超过10第1次453生成5第2次56.4034生成6.403第3次6.4038.1245生成8.124第4次8.12410.3446生成10.344停止—10.3446超过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*ab*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)一定要记住a2b2\boxed{\sqrt{a^2b^2}}错误4不理解ansans不是“计算了几次”。它最终表示第几项第一次超过上限。这两个概念很接近但不要混淆。二十、最后把这道题压缩成一个“万能思维模板”以后遇到这种不断根据前面的数据生成新数据直到满足某个条件可以想成准备初始数据 ↓ 判断有没有结束 ↓ 生成新数据 ↓ 更新旧数据 ↓ 再判断 ↓ …… ↓ 满足结束条件 ↓ 输出答案对应本题就是a、b ↓ b有没有超过U ↓ 没有 ↓ t √(a²b²) ↓ ab bt ↓ 继续 ↓ b U ↓ 输出第几项 一句话记住这道题送给同学们一个非常好记的口诀“两个数字合体开平方根旧 b 变新 a新数字变新 b没超过就继续超过了就停”