三、完整代码实现三、完整代码实现打印十字图
题目描述
小明为某机构设计了一个十字型的徽标(并非红十字会啊),如下所示(可参见下图)
$
$$$$$$$$$$$$$$$$$$$$$$
$$$$
$$$$$$$$$$$$$$$$$$$$$$
$$$$$$$$
$$$$$$$$$$$$$$$$$$
$$$$$$$$$$
$$$$$$$$$$$$$$$$$$
$$$$$$$$$$
$$$$$$$$$$$$$$$$$$
$$$$$$$$
$$$$$$$$$$$$$$$$$$$$$$
$$$$
$$$$$$$$$$$$$$$$$$$$$$
$
对方同时也需要在电脑 dos 窗口中以字符的形式输出该标志,并能任意控制层数。
为了能准确比对空白的数量,程序要求对行中的空白以句点(.)代替。
输入描述
输入一个正整数 n (n<30)n (n<30) 表示要求打印图形的层数。
输出描述
输出对应包围层数的该标志。
输入输出样例
示例
输入
1
输出
..$$$$$..
..$...$..
$$$.$.$$$
$...$...$
$.$$$$$.$
$...$...$
$$$.$.$$$
..$...$..
..$$$$$..
运行限制
- 最大运行时间:1s
- 最大运行内存: 64M
总通过次数: 496 | 总提交次数: 555 | 通过率: 89.4%
难度: 困难 标签: 2013, 模拟, 省赛
C++实现打印十字图:算法详解与代码实现
一、算法思路
十字图由多层嵌套的十字结构组成,每层包含一个主十字和四个角上的小十字。核心思路是分层构建+对称填充,通过数学规律确定关键坐标点。算法步骤如下:
- 初始化画布:创建
(4n+5) × (4n+5)
的二维数组,全部填充为'.'
。 - 绘制核心十字:从中心点开始,按规律绘制垂直和水平方向的十字骨架。
- 分层填充角十字:从内向外逐层绘制四个角上的小十字结构。
- 对称复制:利用中心对称特性,将左上角图形复制到其他三个象限。
- 输出结果:打印最终图形。
数学规律:设总边长
L = 4n + 5
,中心点坐标(c, c) = (L/2, L/2)
。关键坐标通过2*k
(k为层数)的线性组合确定。
二、算法过程图示
n=1 的构建过程(9×9 矩阵):
1. 初始化:全部为 .
.........
.........
.........
.........
.........
.........
.........
.........
.........
2. 绘制核心十字(红色部分):
..$...$.. // 行0: (0,2) (0,6)
..$...$.. // 行1: (1,2) (1,6)
$$$.$.$$$ // 行2: (2,0)(2,1)(2,2)(2,4)(2,6)(2,7)(2,8)
...$... // 行3: (3,4)
...$... // 行4: (4,4)
...$... // 行5: (5,4)
$$$.$.$$$ // 行6: 对称行2
..$...$.. // 行7: 对称行1
..$...$.. // 行8: 对称行0
3. 分层填充角十字(蓝色部分):
角坐标:(0,3)(0,4)(0,5) → 延伸横线
(3,0)(4,0)(5,0) → 延伸竖线
4. 对称复制后得到最终图形:
..$$$$$..
..$...$..
$$$.$.$$$
$...$...$
$.$$$$$.$
$...$...$
$$$.$.$$$
..$...$..
..$$$$$..
三、完整代码实现
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
const int L = 4 * n + 5; // 总边长
char canvas[130][130]; // 画布(最大支持n=30)
// 1. 初始化画布
for (int i = 0; i < L; ++i) {
for (int j = 0; j < L; ++j) {
canvas[i][j] = '.';
}
}
// 2. 绘制核心十字骨架
for (int i = 0; i < 3; ++i) { // 十字的3个基本偏移
for (int j = 0; j <= n; ++j) { // 从中心向外扩展n层
int offset = j * 2;
canvas[i + offset][2 + offset] = '$'; // 垂直方向
canvas[2 + offset][i + offset] = '$'; // 水平方向
}
}
// 3. 分层绘制角十字
for (int j = 0; j < n; ++j) { // j: 当前层数(0~n-1)
int len = 2 * n - 2 * j; // 当前层延伸长度
for (int i = 0; i < len; ++i) { // i: 延伸步长
int start = 2 * j; // 角十字中心X/Y坐标
canvas[start][i + start + 3] = '$'; // 右上横线
canvas[i + start + 3][start] = '$'; // 左下竖线
}
}
// 4. 对称复制(左上→右上→下半)
for (int i = 0; i <= L / 2; ++i) { // 处理上半部分(含中线)
for (int j = 0; j < L; ++j) {
canvas[i][L - 1 - j] = canvas[i][j]; // 左右对称
canvas[L - 1 - i][L - 1 - j] = canvas[i][j]; // 上下对称
}
}
// 5. 输出结果
for (int i = 0; i < L; ++i) {
for (int j = 0; j < L; ++j) {
cout << canvas[i][j];
}
cout << endl;
}
return 0;
}
四、代码解析
画布初始化(L13-L17)
- 创建
L×L
字符数组,L = 4n+5
是十字图边长公式 - 初始填充
'.'
表示空白。
- 创建
核心十字绘制(L20-L25)
- 内层循环
j
控制层数(0~n),offset = 2j
实现层间偏移。 - 外层循环
i
控制十字臂长(0~2覆盖十字的3个点)。
- 内层循环
角十字分层填充(L28-L33)
j
表示当前层(0最内层,n-1最外层)。len = 2n-2j
实现外层延伸更长,内层更短start = 2j
定位角十字中心。
对称复制优化(L36-L40)
- 仅计算左上1/4图形,通过对称得到完整图形。
- 时间复杂度从O(L²)降至O(L²/4),效率提升4倍。
边界处理
- 数组大小130×130满足n<30的需求(最大L=125)。
- 对称循环
i <= L/2
确保中心行被正确处理。
五、实例验证
输入 n=1 时输出:
..$$$$$..
..$...$..
$$$.$.$$$
$...$...$
$.$$$$$.$
$...$...$
$$$.$.$$$
..$...$..
..$$$$$..
输入 n=2 时输出:
..$$$$$$$$$..
..$.......$..
$$$.$$$$$.$$$
$...$...$...$
$.$$$.$.$$$.$
$.$...$...$.$
$.$.$$$$$.$.$
$.$...$...$.$
$.$$$.$.$$$.$
$...$...$...$
$$$.$$$$$.$$$
..$.......$..
..$$$$$$$$$..
六、注意事项
数组越界
- 计算
L=4n+5
后,数组尺寸需 ≥130(n最大29时L=121)。
- 计算
对称覆盖问题
- 对称复制前确保左上1/4图形完全正确。
- 复制循环需包含中心行:
i <= L/2
。
特殊层数处理
- n=0 时程序异常(题目要求n≥1)。
- n≥30 时数组越界(题目限制n<30)。
输出格式
- 行末无空格,每行输出后换行。
- 用
cout
而非printf
避免格式错误。
七、优化建议
内存优化
vector<vector<char>> canvas(L, vector<char>(L, '.')); // 动态分配
效率提升
- 合并绘制循环:将核心十字与角十字的绘制整合到同一循环。
- 减少对称操作:直接计算四个象限坐标。
扩展功能
// 支持彩色输出(Linux终端) void printColor(char c) { if (c == '$') cout << "\033[1;31m$\033[0m"; // 红色$ else cout << "\033[34m.\033[0m"; // 蓝色. }
八、测试用例设计
测试点 | 输入 | 验证重点 |
---|---|---|
边界值n=1 | 1 | 基础图形完整性 |
边界值n=29 | 29 | 数组越界和内存限制 |
奇数层n=3 | 3 | 对称性验证 |
图形连通性 | 2 | 所有$是否连通 |
特殊位置检查 | 任意 | 中心点/四个角是否为$ |
输出格式 | 1 | 行末无空格/无多余空行 |
可通过以下命令进行随机测试:
for n in {1..29}; do ./program < $n.txt; done
九、总结
通过分层构建和对称复制,算法高效实现了十字图的打印。关键点在于:
- 数学建模坐标:
(2k, 2k)
定位角十字中心 - 动态计算延伸长度:
len = 2n-2j
- 对称优化减少计算量