[蓝桥杯]打印十字图

发布于:2025-06-07 ⋅ 阅读:(14) ⋅ 点赞:(0)

三、完整代码实现三、完整代码实现打印十字图

题目描述

小明为某机构设计了一个十字型的徽标(并非红十字会啊),如下所示(可参见下图)

$

$$$$$$$$$$$$$$$$$$$$$$

$$$$

$$$$$$$$$$$$$$$$$$$$$$

$$$$$$$$

$$$$$$$$$$$$$$$$$$

$$$$$$$$$$

$$$$$$$$$$$$$$$$$$

$$$$$$$$$$

$$$$$$$$$$$$$$$$$$

$$$$$$$$

$$$$$$$$$$$$$$$$$$$$$$

$$$$

$$$$$$$$$$$$$$$$$$$$$$

$

对方同时也需要在电脑 dos 窗口中以字符的形式输出该标志,并能任意控制层数。

为了能准确比对空白的数量,程序要求对行中的空白以句点(.)代替。

输入描述

输入一个正整数 n (n<30)n (n<30) 表示要求打印图形的层数。

输出描述

输出对应包围层数的该标志。

输入输出样例

示例

输入

1

输出

..$$$$$..
..$...$..
$$$.$.$$$
$...$...$
$.$$$$$.$
$...$...$
$$$.$.$$$
..$...$..
..$$$$$..

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 64M

总通过次数: 496  |  总提交次数: 555  |  通过率: 89.4%

难度: 困难   标签: 2013, 模拟, 省赛

C++实现打印十字图:算法详解与代码实现

一、算法思路

十字图由多层嵌套的十字结构组成,每层包含一个主十字和四个角上的小十字。核心思路是​​分层构建+对称填充​​,通过数学规律确定关键坐标点。算法步骤如下:

  1. ​初始化画布​​:创建 (4n+5) × (4n+5) 的二维数组,全部填充为 '.'
  2. ​绘制核心十字​​:从中心点开始,按规律绘制垂直和水平方向的十字骨架。
  3. ​分层填充角十字​​:从内向外逐层绘制四个角上的小十字结构。
  4. ​对称复制​​:利用中心对称特性,将左上角图形复制到其他三个象限。
  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;
}
四、代码解析
  1. ​画布初始化​​(L13-L17)

    • 创建 L×L 字符数组,L = 4n+5 是十字图边长公式
    • 初始填充 '.' 表示空白。
  2. ​核心十字绘制​​(L20-L25)

    • 内层循环 j 控制层数(0~n),offset = 2j 实现层间偏移。
    • 外层循环 i 控制十字臂长(0~2覆盖十字的3个点)。
  3. ​角十字分层填充​​(L28-L33)

    • j 表示当前层(0最内层,n-1最外层)。
    • len = 2n-2j 实现外层延伸更长,内层更短
    • start = 2j 定位角十字中心。
  4. ​对称复制优化​​(L36-L40)

    • 仅计算左上1/4图形,通过对称得到完整图形。
    • 时间复杂度从O(L²)降至O(L²/4),效率提升4倍。
  5. ​边界处理​

    • 数组大小130×130满足n<30的需求(最大L=125)。
    • 对称循环 i <= L/2 确保中心行被正确处理。
五、实例验证

​输入 n=1 时输出:​

..$$$$$..
..$...$..
$$$.$.$$$
$...$...$
$.$$$$$.$
$...$...$
$$$.$.$$$
..$...$..
..$$$$$..

​输入 n=2 时输出:​

..$$$$$$$$$..
..$.......$..
$$$.$$$$$.$$$
$...$...$...$
$.$$$.$.$$$.$
$.$...$...$.$
$.$.$$$$$.$.$
$.$...$...$.$
$.$$$.$.$$$.$
$...$...$...$
$$$.$$$$$.$$$
..$.......$..
..$$$$$$$$$..
六、注意事项
  1. ​数组越界​

    • 计算 L=4n+5 后,数组尺寸需 ≥130(n最大29时L=121)。
  2. ​对称覆盖问题​

    • 对称复制前确保左上1/4图形完全正确。
    • 复制循环需包含中心行:i <= L/2
  3. ​特殊层数处理​

    • n=0 时程序异常(题目要求n≥1)。
    • n≥30 时数组越界(题目限制n<30)。
  4. ​输出格式​

    • 行末无空格,每行输出后换行。
    • 用 cout 而非 printf 避免格式错误。
七、优化建议
  1. ​内存优化​

    vector<vector<char>> canvas(L, vector<char>(L, '.')); // 动态分配
  2. ​效率提升​

    • 合并绘制循环:将核心十字与角十字的绘制整合到同一循环。
    • 减少对称操作:直接计算四个象限坐标。
  3. ​扩展功能​

    // 支持彩色输出(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

九、总结

通过分层构建和对称复制,算法高效实现了十字图的打印。关键点在于:

  1. 数学建模坐标:(2k, 2k) 定位角十字中心
  2. 动态计算延伸长度:len = 2n-2j
  3. 对称优化减少计算量

网站公告

今日签到

点亮在社区的每一天
去签到