(判断平方数) 问题:给定一个正整数 $n$,希望判断这个数是否为完全平方数,即存在一个正整数 $x$,使得 $x$ 的平方为 $n$。
试补全程序。
#include<iostream>
#include<vector>
using namespace std;
bool isSquare(int num) {
int i = ___①___;
int bound = ___②___;
for (; i <= bound; ++i) {
if (___③___) {
return ___④___;
}
}
return___⑤___;
}
int main() {
int n;
cin >> n;
if (isSquare(n)) {
cout << n << " is a square number" << endl;
} else {
cout << n << " is not a square number" << endl;
}
return 0;
}1. ① 处应填( ) A. 1 B. 2 C. 3 D. 4 2. ② 处应填( ) A. (int)floor(sqrt(num))-1 B. (int)floor(sqrt(num)) C. floor(sqrt(num/2))-1 D. floor(sqrt(num/2)) 3. ③ 处应填( ) A. num = 2 * i B. num == 2 * i C. num = i * i D. num == i * i 4. ④ 处应填( )(本题有多个可能选项)
(本题为阅读程序 / 完善程序,完整题目与测试数据见平台)
拿到题先想:完全平方数就是存在整数 x 让 x²=n。枚举?从 1 起往上试,但试到哪儿停?直接试到 √n 就行,因为再大 i² 肯定超过 n。上界用 floor(sqrt(n)),循环里只要 i*i==n 就立刻返回 true,跑完都没命中就返回 false。
最容易栽跟头的地方是第③空,把比较符号写成赋值符号 num=i*i,结果条件永远为假,函数永远回 false。还有④⑤两空,找到时该回 true 却顺手写了 false,或者没找到时回 true,逻辑全反了。上界如果算错成 num/2 或者 floor(sqrt(num))-1,会漏掉刚好是平方数的情况(比如 4 的上界算成 1,直接错过 2²=4)。
这道题考查的是枚举法判断完全平方数,属于数论基础与算法枚举的结合点。命题人喜欢在这里挖坑:一是上界算错,二是把比较和赋值搞混,三是 return 的真假弄反。我们一步步把坑填平。
1. 概念与思路 完全平方数的定义很简单:存在一个正整数 x,使得 x 的平方等于给定的 n。要判断 n 是不是完全平方数,最直接的想法就是枚举可能的 x。x 从 1 开始往上试,只要试到某个 i 满足 i*i == n,那就证明 n 是完全平方数,直接返回 true;如果试遍了所有可能的 x 都没找到,那就说明 n 不是完全平方数,返回 false。
2. 确定枚举范围(上界) 枚举不能无休止地进行,必须有一个停止的界限。显然,当 i 超过 sqrt(n) 时,i*i 一定大于 n,不可能再等于 n 了。因此,我们需要遍历 i 从 1 到 floor(sqrt(n))。在 C++ 中,sqrt 返回的是 double 类型,需要强制转换为 int 并向下取整,即 (int)floor(sqrt(num))。如果上界算小了(比如漏掉了刚好是平方数的情况),或者算错了(比如写成 num/2),都会导致程序出错。所以第②空必须填 B 选项。
3. 初始化与循环结构 既然要从 1 开始枚举,第①空自然填 A 选项 1。循环条件 i <= bound 保证了我们会检查到上界。注意,这里用的是 <=,而不是 <,因为上界本身可能就是答案(比如 n=4,上界是 2,2*2=4 正好成立)。
4. 判断条件与返回值 循环体内,我们需要判断当前的 i 是否满足 i*i == n。这里有两个极易混淆的点:
= 是赋值,== 才是相等比较。如果填成 num = i * i(选项 A),相当于把 i*i 赋给 num,然后判断这个赋值表达式的结果(非零即为真),这逻辑完全不对。必须填 D 选项 num == i * i。true(选项 C)。如果没找到,循环自然结束,最后返回 false(选项 D)。5. 命题人的挖坑视角 这道题虽然简单,但命题人很狡猾。第③空给了一个陷阱选项 A,就是把比较符号写成赋值,这是初学者最容易犯的错误。第④空虽然官方答案给了 C 和 A 两个选项(可能是排版或逻辑上的宽容),但核心是找到就回 true。第⑤空如果填成了 true,那整个逻辑就反了。另外,上界如果填成 (int)floor(sqrt(num))-1(选项 A),对于 n=4 这种完全平方数,上界就变成了 1,循环只检查了 1*1=1,直接漏掉了 2*2=4,导致误判为不是完全平方数。这些都是典型的“会算但算错”的坑。
6. 考频与趋势分析 从题库数据来看,算法类题目总共考过 7 题,覆盖 4 个级别,其中 2024 年考了 2 题,2025 年考了 1 题,说明这类基础算法题在入门级和普及组中依然高频出现,且逐年分布较为均匀,没有明显的断档。枚举法更是题库中的常客,共考过 159 题,覆盖 9 个级别,2024 年考了 6 题,2025 年考了 6 题,2026 年甚至考了 13 题,呈现明显的上升趋势,说明枚举思想在各类竞赛中越来越受重视。数论基础类题目共 28 题,2024 年考了 3 题,2026 年考了 11 题,也显示出数论相关考点在近期考试中的活跃度。
7. 预测 基于上述数据,枚举法和数论基础在 CSP 入门级、NOIP 普及组以及 GESP 考试中属于核心考点,且近年考频不降反升。未来(2026 及以后)这类题目仍会频繁出现,命题形式可能更加灵活,比如结合其他基础算法(如二分查找、贪心)进行综合考察,或者在数据范围上增加对边界情况的考验(如极大数、极小数)。因此,学生必须熟练掌握枚举的上界计算、条件判断以及返回值逻辑,不能仅凭直觉做题。
8. 完整代码与验证 将上述分析填入代码,得到的完整函数如下:
bool isSquare(int num) {
int i = 1;
int bound = (int)floor(sqrt(num));
for (; i <= bound; ++i) {
if (num == i * i) {
return true;
}
}
return false;
}拿几个典型数据验证一下:
所有测试均通过,说明逻辑无误。
总结 这道题看似简单,实则涵盖了枚举法的核心要素:确定范围、编写循环、条件判断、返回值。命题人喜欢在细节处设坑,如比较符号、上界计算、真假返回值等。学生在复习时,不仅要记住“枚举到 sqrt(n)”,更要理解为什么是 sqrt(n),以及每一步代码的具体含义。只有把这些细节吃透,才能在考试中稳稳拿下这类题目,避免因为粗心而丢分。