202606-菱形(luogu-B4554)

202606-菱形(luogu-B4554)

GESP C++二级,2026年6月真题,嵌套循环与字符图形绘制,难度⭐⭐,洛谷难度普及-

luogu-B4554 [GESP202606 二级] 菱形

题目要求

题目描述

给定正整数 nn,在 (2n1)×(2n1)(2n - 1) \times (2n - 1) 个网格的画布中,使用字符画一个边长为 nn 个网格的菱形。其中,空白网格使用 .. 表示,菱形边所在的网格用 ++ 表示。

例如当 n=3n = 3 时,图形如下:

..+..
.+.+.
+...+
.+.+.
..+..

输入格式

输入一个正整数 nn

输出格式

输出 2n12n - 1 行,表示按要求画的菱形。

输入输出样例 #1

输入 #1

4

输出 #1

...+...
..+.+..
.+...+.
+.....+
.+...+.
..+.+..
...+...

说明/提示

数据范围

3n153 \le n \le 15


题目分析

解题思路

本题的解题思路如下:

  1. 问题本质:

    • (2n1)×(2n1)(2n-1) \times (2n-1) 的网格中绘制一个菱形
    • 菱形的中心在第 nn 行第 nn 列(从 11 开始计数),边长为 nn
    • 菱形边上的格子用 + 表示,其余用 . 表示
  2. 解题关键 — 判断菱形边上的点:

    • 菱形上的点满足条件:与中心点的曼哈顿距离恰好等于 n1n - 1
    • 即对于第 ii 行第 jj 列(均从 00 开始计数),若 i(n1)+j(n1)=n1\|i - (n-1)\| + \|j - (n-1)\| = n - 1,则该位置是菱形边上的点
    • 也可以分上下两半来理解:
      • 上半部分(第 00n1n-1 行):第 ii 行的 + 出现在第 n1in-1-i 列和第 n1+in-1+i
      • 下半部分(第 nn2n22n-2 行):与上半部分关于中间行对称
    • 特殊情况:第 00 行和第 2n22n-2 行只有一个 +(菱形的上下顶点)
  3. 复杂度分析:

    • 时间复杂度:O(n2)O(n^2),需要遍历 (2n1)×(2n1)(2n-1) \times (2n-1) 的网格
    • 空间复杂度:O(1)O(1),只需常数个变量

示例代码

方法一、利用曼哈顿距离判断

通过判断每个位置与菱形中心的曼哈顿距离是否等于 n1n - 1,来确定该位置是否为菱形边上的点。

#include <iostream>
#include <cmath>

int main() {
    // 读入菱形的边长
    int n;
    std::cin >> n;
    // 网格大小为 (2n-1) x (2n-1)
    int size = 2 * n - 1;
    // 菱形中心位置(行列下标均为 n-1)
    int center = n - 1;
    // 遍历每一行
    for (int i = 0; i < size; i++) {
        // 遍历每一列
        for (int j = 0; j < size; j++) {
            // 计算当前位置到中心的曼哈顿距离
            // 若距离恰好等于 n-1,则该位置是菱形边上的点
            if (std::abs(i - center) + std::abs(j - center) == n - 1) {
                std::cout << "+";
            } else {
                std::cout << ".";
            }
        }
        // 每行结束后换行
        std::cout << std::endl;
    }
    return 0;
}

方法二、分别计算每行的 + 位置

根据每一行到中心行的距离,直接计算 + 出现的列号,逐字符输出。

#include <iostream>

int main() {
    // 读入菱形的边长
    int n;
    std::cin >> n;
    // 网格大小为 (2n-1) x (2n-1)
    int size = 2 * n - 1;
    // 遍历每一行
    for (int i = 0; i < size; i++) {
        // 计算当前行到中心行的距离
        int dist;
        if (i < n) {
            dist = n - 1 - i;
        } else {
            dist = i - (n - 1);
        }
        // 第 i 行的 '+' 出现在第 dist 列和第 size - 1 - dist 列
        for (int j = 0; j < size; j++) {
            if (j == dist || j == size - 1 - dist) {
                std::cout << "+";
            } else {
                std::cout << ".";
            }
        }
        // 每行结束后换行
        std::cout << std::endl;
    }
    return 0;
}

本文由coderli.com原创,按照CC BY-NC-SA 4.0 进行授权

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

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

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

GESP/CSP认证交流QQ群: 688906745

GESP/CSP 认证学习微信公众号
GESP/CSP 认证学习微信公众号
最后更新于