7 多层循环结构(二)循环嵌套综合应用
正在加载视频播放器…
GESP C++ 二级:多层循环结构(二)循环嵌套综合应用
核心目标:在掌握嵌套
for循环的基础上,综合运用多层循环与分支、数位拆分、数学函数,解决枚举、图形打印、数学统计、数位处理等综合问题。
外层控制主变量,内层控制次变量;循环负责遍历,分支负责筛选;累加计数变量位置要正确,break/continue只作用于当前层。
一、综合应用核心思想
循环嵌套综合题,通常由以下要素组合而成:
| 要素 | 作用 | 示例 |
|---|---|---|
| 外层循环 | 控制主要变量,如行、枚举的第一个数 | for (int i = 1; i <= n; i++) |
| 内层循环 | 控制次要变量,如列、枚举的第二个数 | for (int j = 1; j <= m; j++) |
| 分支判断 | 筛选满足条件的组合或控制图形 | if (i + j == 50) |
| 累加/计数 | 统计满足条件的个数或求和 | cnt++、sum += ... |
| 数位拆分 | 处理整数的每一位 | n % 10、n / 10 |
| 数学函数 | 辅助计算 | sqrt、abs、pow |
综合题解题步骤:
- 确定需要枚举哪些变量。
- 确定每个变量的范围。
- 确定循环嵌套层次。
- 在内层写条件判断。
- 在合适位置累加、计数或输出。
- 检查边界、初始化和输出格式。
二、循环嵌套与分支结合
1. 筛选满足条件的数
例:输出 1~100 中能被 3 整除且能被 5 整除的数。
for (int i = 1; i <= 100; i++) {
if (i % 3 == 0 && i % 5 == 0) {
cout << i << " ";
}
}
输出:
15 30 45 60 75 90
2. 双层循环筛选组合
例:求 1~9 中,两个数之和为 10 的组合。
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= 9; j++) {
if (i + j == 10) {
cout << i << "+" << j << "=10" << endl;
}
}
}
3. 计数
例:统计 1~100 中有多少对数 (i, j) 满足 i + j = 50 且 i < j。
int cnt = 0;
for (int i = 1; i <= 100; i++) {
for (int j = 1; j <= 100; j++) {
if (i + j == 50 && i < j) {
cnt++;
}
}
}
cout << cnt << endl;
4. 累加
例:求 1~n 中所有偶数的和。
int sum = 0;
for (int i = 1; i <= n; i++) {
if (i % 2 == 0) {
sum += i;
}
}
cout << sum << endl;
重点:
sum和cnt必须定义在循环外,循环内只更新。
三、枚举法(穷举法)
枚举法就是把所有可能的情况一一列举出来,用条件筛选出正确答案。
1. 百钱百鸡
公鸡 5 元一只,母鸡 3 元一只,小鸡 1 元三只。100 元买 100 只鸡,求所有方案。
for (int x = 0; x <= 20; x++) { // 公鸡最多 20 只
for (int y = 0; y <= 33; y++) { // 母鸡最多 33 只
int z = 100 - x - y; // 小鸡数量
if (z >= 0 && 5 * x + 3 * y + z / 3 == 100 && z % 3 == 0) {
cout << x << " " << y << " " << z << endl;
}
}
}
输出:
0 25 75
4 18 78
8 11 81
12 4 84
2. 鸡兔同笼
头共 h 个,脚共 f 只,求鸡和兔各多少。
for (int chicken = 0; chicken <= h; chicken++) {
int rabbit = h - chicken;
if (2 * chicken + 4 * rabbit == f) {
cout << chicken << " " << rabbit << endl;
}
}
3. 水仙花数
三位数,各位数字立方和等于本身。
for (int n = 100; n <= 999; n++) {
int a = n / 100;
int b = n / 10 % 10;
int c = n % 10;
if (a*a*a + b*b*b + c*c*c == n) {
cout << n << " ";
}
}
输出:
153 370 371 407
4. 完数
一个数等于它的所有真因子之和,如 6 = 1+2+3。
for (int n = 2; n <= 1000; n++) {
int sum = 0;
for (int i = 1; i < n; i++) {
if (n % i == 0) {
sum += i;
}
}
if (sum == n) {
cout << n << " ";
}
}
输出:
6 28 496
四、图形打印进阶
1. 空心矩形
输入 n 行 m 列,边界打印 *,内部打印空格。
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (i == 1 || i == n || j == 1 || j == m) {
cout << "*";
} else {
cout << " ";
}
}
cout << endl;
}
输入 4 6,输出:
******
* *
* *
******
2. 等腰三角形
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n - i; j++) cout << " ";
for (int j = 1; j <= 2 * i - 1; j++) cout << "*";
cout << endl;
}
输入 4,输出:
*
***
*****
*******
3. 菱形
int n;
cin >> n;
// 上半部分
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n - i; j++) cout << " ";
for (int j = 1; j <= 2 * i - 1; j++) cout << "*";
cout << endl;
}
// 下半部分
for (int i = n - 1; i >= 1; i--) {
for (int j = 1; j <= n - i; j++) cout << " ";
for (int j = 1; j <= 2 * i - 1; j++) cout << "*";
cout << endl;
}
输入 4,输出:
*
***
*****
*******
*****
***
*
4. 数字金字塔
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n - i; j++) cout << " ";
for (int j = 1; j <= i; j++) cout << j;
for (int j = i - 1; j >= 1; j--) cout << j;
cout << endl;
}
输入 4,输出:
1
121
12321
1234321
5. 九九乘法表
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
cout << j << "*" << i << "=" << i * j << " ";
}
cout << endl;
}
五、数学问题综合
1. 求 1~n 中所有素数
for (int i = 2; i <= n; i++) {
bool isPrime = true;
for (int j = 2; j * j <= i; j++) {
if (i % j == 0) {
isPrime = false;
break;
}
}
if (isPrime) {
cout << i << " ";
}
}
2. 求 1! + 2! + ... + n!
long long sum = 0;
for (int i = 1; i <= n; i++) {
long long fac = 1;
for (int j = 1; j <= i; j++) {
fac *= j;
}
sum += fac;
}
cout << sum << endl;
3. 求最大公约数(辗转相除法)
int a, b;
cin >> a >> b;
while (b != 0) {
int t = a % b;
a = b;
b = t;
}
cout << a << endl;
4. 求最小公倍数
int lcm = a * b / gcd(a, b);
5. 统计 1~n 中数字 k 出现的次数
int cnt = 0;
for (int i = 1; i <= n; i++) {
int t = i;
while (t > 0) {
if (t % 10 == k) cnt++;
t /= 10;
}
}
cout << cnt << endl;
六、数位拆分与循环嵌套
1. 求所有数位和为指定值的数
for (int i = 1; i <= 1000; i++) {
int t = i, sum = 0;
while (t > 0) {
sum += t % 10;
t /= 10;
}
if (sum == 9) {
cout << i << " ";
}
}
2. 数字反转后相加
int n;
cin >> n;
int t = n, rev = 0;
while (t > 0) {
rev = rev * 10 + t % 10;
t /= 10;
}
cout << n + rev << endl;
3. 回文数判断
int t = n, rev = 0;
while (t > 0) {
rev = rev * 10 + t % 10;
t /= 10;
}
if (rev == n) cout << "回文数";
else cout << "不是回文数";
七、常见综合模型与模板
| 模型 | 核心代码模板 |
|---|---|
| 双层枚举 | for (i...) for (j...) if (条件) ... |
| 计数 | cnt = 0; ... if (条件) cnt++; |
| 累加 | sum = 0; ... sum += ...; |
| 求素数 | 外层遍历,内层 2 ~ sqrt(i) 判断 |
| 完数 | 外层遍历,内层求因子和 |
| 水仙花数 | 外层 100~999,数位拆分 |
| 百钱百鸡 | 双层枚举,第三量由总数推出 |
| 鸡兔同笼 | 枚举鸡,兔由头数推出 |
| 图形打印 | 外层行,内层列;空格 + 星号 |
| 数字三角形 | 内层 j <= i |
| 菱形 | 上半 + 下半,空格递减/递增 |
| 数位统计 | 外层遍历,内层 while (t > 0) |
| 最大公约数 | while (b != 0) 辗转相除 |
八、易错点
-
累加/计数变量初始化位置错误
for (...) { int sum = 0; // 错误:每次循环都清零 }应定义在循环外。
-
循环变量重名
for (int i = 1; i <= n; i++) for (int i = 1; i <= m; i++) // 错误 -
break只跳出内层
需要跳出多层时用标志变量。 -
continue跳过更新导致死循环while (i < n) { if (条件) continue; i++; } -
循环边界错误
i < n与i <= n结果不同。 -
整数除法丢小数
double avg = sum / n; // 错误,应 1.0 * sum / n -
数位拆分忘记特判 0
0 的位数是 1。 -
图形打印换行位置错误
换行放在内层循环结束后、外层循环内。 -
输出格式错误
注意空格、换行,严格按题目要求。 -
溢出
大数用long long,乘法可写1LL * a * b。 -
浮点数比较
不要直接用==。 -
死循环
循环变量未更新或条件永远为真。
九、阅读程序写结果
题目 1
int cnt = 0;
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 5; j++) {
if (i + j == 6) cnt++;
}
}
cout << cnt << endl;
输出:
5
题目 2
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= i; j++) {
cout << j;
}
cout << endl;
}
输出:
1
12
123
1234
题目 3
int sum = 0;
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
sum += i * j;
}
}
cout << sum << endl;
输出:
36
题目 4
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 5; j++) {
if (j == 3) break;
cout << i << j << " ";
}
cout << endl;
}
输出:
11 12
21 22
31 32
41 42
51 52
题目 5
for (int n = 100; n <= 999; n++) {
int a = n / 100;
int b = n / 10 % 10;
int c = n % 10;
if (a*a*a + b*b*b + c*c*c == n) {
cout << n << " ";
}
}
输出:
153 370 371 407
十、编程题示例
1. 输出 1~n 中所有素数
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
for (int i = 2; i <= n; i++) {
bool isPrime = true;
for (int j = 2; j * j <= i; j++) {
if (i % j == 0) {
isPrime = false;
break;
}
}
if (isPrime) cout << i << " ";
}
return 0;
}
2. 百钱百鸡
#include <iostream>
using namespace std;
int main() {
for (int x = 0; x <= 20; x++) {
for (int y = 0; y <= 33; y++) {
int z = 100 - x - y;
if (z >= 0 && 5 * x + 3 * y + z / 3 == 100 && z % 3 == 0) {
cout << x << " " << y << " " << z << endl;
}
}
}
return 0;
}
3. 打印菱形
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n - i; j++) cout << " ";
for (int j = 1; j <= 2 * i - 1; j++) cout << "*";
cout << endl;
}
for (int i = n - 1; i >= 1; i--) {
for (int j = 1; j <= n - i; j++) cout << " ";
for (int j = 1; j <= 2 * i - 1; j++) cout << "*";
cout << endl;
}
return 0;
}
4. 统计 1~n 中数字 k 出现次数
#include <iostream>
using namespace std;
int main() {
int n, k;
cin >> n >> k;
int cnt = 0;
for (int i = 1; i <= n; i++) {
int t = i;
while (t > 0) {
if (t % 10 == k) cnt++;
t /= 10;
}
}
cout << cnt << endl;
return 0;
}
十一、速查表
| 需求 | 写法 |
|---|---|
| 双层枚举 | for (i...) for (j...) if (条件) ... |
| 计数 | cnt = 0; ... if (条件) cnt++; |
| 累加 | sum = 0; ... sum += ...; |
| 求素数 | 外层遍历,内层 2 ~ sqrt(i) |
| 完数 | 外层遍历,内层求因子和 |
| 水仙花数 | 100~999,数位拆分 |
| 百钱百鸡 | 双层枚举,第三量推出 |
| 鸡兔同笼 | 枚举鸡,兔由头数推出 |
| 空心矩形 | 边界判断 i==1 || i==n || j==1 || j==m |
| 等腰三角形 | 空格 n-i,星号 2*i-1 |
| 菱形 | 上半 + 下半 |
| 数字金字塔 | 空格 + 升序 + 降序 |
| 数位统计 | 外层遍历,内层 while (t > 0) |
| 最大公约数 | while (b != 0) 辗转相除 |
| 跳出内层 | break |
| 跳过本次 | continue |
| 跳出多层 | 标志变量 |
十二、总结
循环嵌套综合应用是 GESP 二级的核心难点。
- 外层控制主变量,内层控制次变量。
- 循环负责遍历,分支负责筛选。
- 枚举法就是列举所有可能,用条件筛选。
- 累加变量初始化为 0,累乘变量初始化为 1。
- 计数和累加变量必须定义在循环外。
break只跳出当前层,continue只跳过当前层本次。- 图形打印注意空格、星号、换行位置。
- 数位拆分用
% 10和/ 10,注意特判 0。 - 大数用
long long,防止溢出。 - 输出格式严格按题目要求,不多空格、不多换行。
复习建议:多练“阅读程序写结果”“图形打印”“枚举法”“数位统计”四类题,重点注意循环边界、变量初始化、break/continue 作用范围、整数除法和输出格式。考试中先确定枚举变量和范围,再写循环和条件,最后逐行模拟验证。