文章

【GESP】C++二级真题 luogu-B4498, [GESP202603 二级] 画画

2026年3月,GESP二级真题,考察双重循环在控制台图形打印中的应用,难度★★☆☆☆。洛谷难度等级:入门

B4498 [GESP202603 二级] 画画

题目要求

题目描述

输入一个正整数 $n$,你需要绘制一个 $n$ 行 $n$ 列的正方形,绘制规则如下:

  • 正方形的四个顶点使用 + 绘制;
  • 除顶点外,第 $1$ 行与第 $n$ 行使用 - 绘制;
  • 除顶点外,第 $1$ 列与第 $n$ 列使用 | 绘制;
  • 正方形内部使用 * 绘制。

输入格式

一行,一个正整数 $n$。

输出格式

输出共 $n$ 行,表示对应的正方形。

输入输出样例 #1

输入 #1

1
5

输出 #1

1
2
3
4
5
+---+
|***|
|***|
|***|
+---+

说明/提示

数据范围

保证 $3 \leq n \leq 100$。


题目分析

这道题目是经典的控制台图形打印问题。在 GESP 二级中,双重循环是必考核心知识点,而图形打印是检验学生对双重循环行列坐标($i, j$ 变量)控制能力最直接的方式。

我们可以把这个 $n \times n$ 的正方形看成一个矩阵。外层循环控制行(一般用变量 i,从 1 到 $n$),内层循环控制列(一般用变量 j,也是从 1 到 $n$)。

对于矩阵中的每一个位置 $(i, j)$,我们需要根据它所在的行和列的特征,判断应该输出什么字符。题目规则非常清晰,我们可以按以下优先级进行判断:

  1. 判断顶点: 顶点位于四个角上。即行等于 1 或 $n$,并且 列也等于 1 或 $n$。
    • 左上角:i == 1 && j == 1
    • 右上角:i == 1 && j == n
    • 左下角:i == n && j == 1
    • 右下角:i == n && j == n
    • 综合起来,可以写为:(i == 1 || i == n) && (j == 1 || j == n)。属于这种情况的,打印 +
  2. 判断上下边框(除顶点外): 第一行或第 $n$ 行。在前一步已经排除了顶点的情况下,只要 i == 1 或者 i == n,就打印 -

  3. 判断左右边框(除顶点外): 第一列或第 $n$ 列。同样在排除了顶点的情况下,只要 j == 1 或者 j == n,就打印 |

  4. 内部区域: 既不是顶点,也不是上下边界,也不是左右边界的区域,统统打印 *

使用经典的 if-else if-else 结构即可完美覆盖这几种互斥的情况。


示例代码

标准双重循环解法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>

int main() {
    int n;
    std::cin >> n;

    // 外层循环控制行,i 从 1 到 n
    for (int i = 1; i <= n; i++) {
        // 内层循环控制列,j 从 1 到 n
        for (int j = 1; j <= n; j++) {

            // 规则 1:判断是否是四个顶点
            // 行是第1行或第n行,同时列是第1列或第n列
            if ((i == 1 || i == n) && (j == 1 || j == n)) {
                std::cout << "+";
            }
            // 规则 2:判断是否是上下边缘(排除顶点后)
            // 如果是第1行或者第n行,打印 '-'
            else if (i == 1 || i == n) {
                std::cout << "-";
            }
            // 规则 3:判断是否是左右边缘(排除顶点后)
            // 如果是第1列或者第n列,打印 '|'
            else if (j == 1 || j == n) {
                std::cout << "|";
            }
            // 规则 4:正方形内部区域
            // 其他所有情况,打印 '*'
            else {
                std::cout << "*";
            }

        } // 结束当前行的打印

        // 这一行的内容全部横向打印完毕,输出换行符,准备打印下一行
        std::cout << std::endl;
    }

    return 0;
}

代码解析小贴士

  1. 逻辑顺序很重要:if-else if 结构中,先判断条件最苛刻(最特殊)的,再判断泛化的条件。在这道题里,顶点是最特殊的元素,它既属于第一、$N$行,又属于第一、$N$列,必须优先用 if 判断并拦截掉。如果在最开始先判断 i == 1 画横线,那么这行两端的十字架会被错误地画成横线,从而导致输出错误。
  2. 坐标体系: 初学者容易搞混控制台里的“坐标系”和数学里的平面直角坐标系(笛卡尔坐标系)。在编程画图时,屏幕的最左上角才是真正的原点 (1, 1)。行变量 i 控制 $y$ 轴方向向下增长,列变量 j 控制 $x$ 轴方向向右增长。每次循环结束后记得显式输出一个换行std::cout << std::endl 或者 \n)。

所有代码已上传至Github:https://github.com/lihongzheshuai/yummy-code

GESP 学习专题站:GESP WIKI

luogu-”系列题目可在洛谷题库进行在线评测。

bcqm-”系列题目可在编程启蒙题库进行在线评测。

欢迎加入Java、C++、Python技术交流QQ群(982860385),大佬免费带队,有问必答

欢迎加入C++ GESP/CSP认证学习QQ频道,考试资源总结汇总

欢迎加入C++ GESP/CSP学习交流QQ群(688906745),考试认证学员交流,互帮互助

GESP/CSP 认证学习微信公众号
GESP/CSP 认证学习微信公众号
本文由作者按照 CC BY-NC-SA 4.0 进行授权