C++数字直角三角形生成:循环结构与格式化输出详解(洛谷P5721)
·

题目分析与关键要求
题目描述
输入正整数n(1 ≤ n ≤ 13),输出一个直角边长度为n的数字直角三角形,满足以下要求:
- 所有数字由递增的两位数组成(包含前导0)
- 直角位于左上角(第一行元素最多)
- 每条直角边的长度均为n
输入输出样例
输入:5 输出:
0102030405
06070809
101112
1314
15
解题思路与算法设计
关键需求分解
- 数字序列:连续的两位数,从01开始递增
- 行结构:第一行n个元素,每行递减1个
- 格式要求:统一为两位数,不足补前导0
算法流程图

C++代码解析与优化
基础实现代码
#include <iostream>
#include <cstdio> // 使用printf进行格式化输出
using namespace std;
int main() {
int n;
cin >> n; // 输入三角形的直角边长
int a = 1; // 初始化起始数字为1
for (int i = n; i >= 1; i--) { // 外层循环控制行数
for (int j = i; j >= 1; j--) { // 内层循环控制当前行元素数量
printf("%02d", a++); // 输出两位数并自增变量
}
cout << endl; // 每行结束换行
}
return 0;
}
核心知识点详解
1. 循环嵌套结构
for (int i = n; i >= 1; i--) { // i从n递减到1
for (int j = i; j >= 1; j--) { // j从当前i递减到1
// 元素输出代码
}
// 换行代码
}
- 外层循环:控制总的行数(n行)
- 内层循环:控制每行元素数量(第1行n个,第n行1个)
- 递减设计:使内层循环次数逐行递减
2. 格式化输出
printf("%02d", a++);
%02d:格式化输出整数0:宽度不足时用0填充2:输出总宽度为2位d:输出十进制整数
a++:先输出当前值,再自增
3. 数字序列生成技巧
a从1开始,每次输出后自增- 自动处理数字递增逻辑
- 不需要单独计算每个位置的值
代码优化方案
1. 减少变量数量
int main() {
int n, a = 1;
cin >> n;
while (n) {
int cnt = n--;
while (cnt--)
printf("%02d", a++);
cout << endl;
}
return 0;
}
2. 使用C++流格式化
#include <iostream>
#include <iomanip> // 控制输出格式
using namespace std;
int main() {
int n, a = 1;
cin >> n;
for (int row = n; row >= 1; row--) {
for (int col = 0; col < row; col++) {
cout << setfill('0') << setw(2) << a++;
}
cout << endl;
}
return 0;
}
setfill('0'):设置填充字符为'0'setw(2):设置输出宽度为2位
3. 预分配数字数组方案
#include <iostream>
#include <vector>
#include <iomanip>
using namespace std;
int main() {
int n;
cin >> n;
// 计算总数字个数:三角形数公式
int total = n*(n+1)/2;
vector<int> numbers(total);
// 初始化数字序列
for (int i = 0; i < total; i++) {
numbers[i] = i+1;
}
// 分层输出
int start = 0;
for (int row = n; row >= 1; row--) {
for (int i = 0; i < row; i++) {
cout << setfill('0') << setw(2) << numbers[start+i];
}
start += row;
cout << endl;
}
return 0;
}
关键编程技巧详解
1. 循环控制优化
循环方向选择
// 递减方式(推荐)
for (int i = n; i > 0; i--) {
for (int j = i; j > 0; j--) {
// 输出元素
}
}
// 递增方式
for (int i = 0; i < n; i++) {
for (int j = 0; j < n - i; j++) {
// 输出元素
}
}
推荐递减方式原因:
- 不需要计算偏移量
- 更直观的反应行元素数量
- 减少变量计算次数
2. 数字格式化详解
不同格式化方法比较
| 方法 | 代码实现 | 优点 | 缺点 |
|---|---|---|---|
printf |
printf("%02d", num) |
简洁高效 | 需要C标准库 |
| 流操作符 | cout << setfill('0') << setw(2) << num |
C++标准 | 冗长 |
| 条件语句 | if(num<10) cout<<"0"; cout<<num; |
直观 | 代码重复 |
格式化应用场景
// 简单数字输出
printf("%02d", num);
// 复杂格式化(如包含字符)
printf("%02d-%c", id, 'A'+type);
// 对齐表格输出
printf("%-6s|%02d", name, id);
3. 边界条件处理
输入验证
cin >> n;
// 验证输入范围
if (n < 1 || n > 13) {
cerr << "输入超出范围:1 <= n <= 13" << endl;
return 1;
}
输出验证
// 预期最大值计算
int max_num = n*(n+1)/2;
if (max_num <= 99) {
// 确保两位数足够
} else {
// 处理三位数(超出题目范围)
}
题目变式与扩展
变式1:右下角直角三角形
#include <iostream>
#include <cstdio>
using namespace std;
int main() {
int n, a = 1;
cin >> n;
for (int i = 1; i <= n; i++) {
// 打印前方空格
for (int sp = n - i; sp > 0; sp--) {
cout << " "; // 两位数宽的空格
}
// 打印数字
for (int j = 0; j < i; j++) {
printf("%02d", a++);
}
cout << endl;
}
return 0;
}
输出n=5的结果:
01
0203
040506
07080910
1112131415
变式2:字母直角三角
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n;
char ch = 'A';
cin >> n;
for (int i = n; i > 0; i--) {
for (int j = i; j > 0; j--) {
cout << ch++ << " "; // 字母递增
}
cout << endl;
}
return 0;
}
输出n=5的结果:
A B C D E
F G H I
J K L
M N
O
变式3:斐波那契三角
#include <iostream>
#include <iomanip>
#include <vector>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> fib = {1, 1}; // 斐波那契序列
// 生成足够的斐波那契数
for (int i = 2; i < n*(n+1)/2; i++) {
fib.push_back(fib[i-1] + fib[i-2]);
}
int index = 0;
for (int row = n; row > 0; row--) {
for (int col = 0; col < row; col++) {
cout << setw(4) << fib[index++];
}
cout << endl;
}
return 0;
}
竞赛技巧与常见错误
1. 格式化输出常见错误
// 错误示范1:忘记设置填充字符
printf("%2d", num); // 不足时用空格填充
// 错误示范2:流操作顺序错误
cout << setw(2) << setfill('0') << num; // 应先设置fill
// 解决方案:
cout << setfill('0') << setw(2) << num;
2. 循环边界陷阱
// 错误示范:数组下标越界
int numbers[n]; // n不是编译期常量
// 正确做法:
int *numbers = new int[n];
// 或使用vector
vector<int> nums(n);
3. 整数溢出风险
// 当n=13时,最大数字为13*14/2=91
// 但n>13时,例如n=20,最大数字为210(三位数)
// 需添加检测
if (a > 99) {
printf("%3d", a); // 改为三位显示
}
典型题目推荐
| 题目 | 平台 | 核心知识点 |
|---|---|---|
| 数字金字塔 | 洛谷P1030 | 循环输出/格式化 |
| 字母直角三角 | CodeForces #118A | 字符处理 |
| 螺旋矩阵 | LeetCode #54 | 二维数组处理 |
| 斐波那契三角 | HDU #1207 | 数学序列 |
| 数字直角三角形 | CSP-J模拟题 | 综合应用 |
"循环与格式化输出是CSP-J/S竞赛的基础功,掌握不同输出格式的区别,能大幅提升解题效率。" —— NOI金牌选手经验谈
总结与学习建议
核心知识点清单
- 循环结构:嵌套循环的设计与优化
- 格式化输出:
printf格式字符串(%02d)- 流操作符(
setw,setfill)
- 二维形状生成:理解坐标系与元素定位
- 边界处理:输入验证与溢出检测
训练建议
- 基础练习:实现不同方向(上/下/左/右)的直角三角形
- 进阶练习:生成数字金字塔、字母矩阵等复杂图形
- 挑战练习:尝试动态分配空间处理更大n值
- 在线提交:在洛谷、Codeforces等平台搜索相关题目
更多推荐

所有评论(0)