题解:洛谷 B4554 菱形

【题目来源】

洛谷:B4554 [GESP202606 二级] 菱形 - 洛谷

【题目描述】

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

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

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

【输入】

输入一个正整数 \(n\)

【输出】

输出 \(2n - 1\) 行,表示按要求画的菱形。

【输入样例】

4

【输出样例】

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

【核心思想】

  1. 问题分析:给定正整数 \(n\),在 \((2n-1) \times (2n-1)\) 的画布上绘制边长为 \(n\) 的菱形边框。菱形中心位于画布中心 \((n, n)\),边框由 + 组成,其余位置为 .。关键观察是:菱形的上半部分和下半部分关于中心行对称,每行的 + 出现在两个对称位置,且距离中心列的偏移量随远离中心而增大。

  2. 算法选择

    • 对称绘制法:将菱形分为上半部分(含中心行)和下半部分(含中心行),利用对称性分别绘制
    • 边界收缩/扩展:用双指针 \(l\)\(r\) 表示当前行菱形边框的左右列坐标,上半部分 \(l\) 递减、\(r\) 递增,下半部分同理
  3. 关键步骤

    • 初始化画布:创建 \((2n-1) \times (2n-1)\) 的字符矩阵,全部填充为 .
    • 确定中心:中心位置为 \((n, n)\),初始化 \(l = r = n\)
    • 绘制上半部分\(i\)\(1\)\(n\)):
      • \((i, l)\)\((i, r)\) 处标记 +
      • \(l \leftarrow l - 1\)\(r \leftarrow r + 1\)(下一行菱形变宽)
    • 绘制下半部分\(i\)\(2n-1\)\(n\)):
      • 重置 \(l = r = n\),从底部向中心行绘制
      • \((i, l)\)\((i, r)\) 处标记 +
      • \(l \leftarrow l - 1\)\(r \leftarrow r + 1\)(上一行菱形变宽)
    • 输出画布:按行输出矩阵
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n^2)\),初始化画布 \(O(n^2)\),绘制边框 \(O(n)\),输出 \(O(n^2)\)
    • 空间复杂度:\(O(n^2)\),存储 \((2n-1) \times (2n-1)\) 的画布矩阵
  5. 对称绘制法的核心思想

    • 几何对称性利用:菱形关于水平中心线和垂直中心线均对称,因此只需计算一侧的坐标规律,通过对称复制完成另一半
    • 双指针控制边界\(l\)\(r\) 从中心列向两侧扩展,每行偏移量增加 \(1\),精确刻画菱形边框的斜线特征(斜率为 \(\pm 1\)
    • 先填充后覆盖:先将整个画布置为 .,再在特定位置覆盖 +,避免复杂的条件判断,简化绘制逻辑
    • 中心行重复绘制:上半部分和下半部分的循环均包含中心行,导致中心行的两个 + 被绘制两次(效果相同),代码简洁但存在冗余
    • 适用于规则几何图形的字符画绘制,尤其是具有对称性的多边形边框生成

【算法标签】

普及- #模拟

【代码详解】

#include <bits/stdc++.h>
using namespace std;
const int N = 20;                  // 常量:数组最大尺寸

char a[2 * N][2 * N];              // a[i][j]: 画布上第 i 行第 j 列的字符
int n;                             // n: 菱形边长

int main()
{
    cin >> n;                      // 读入菱形边长 n

    for (int i = 1; i <= 2 * n - 1; i++)      // 初始化画布:全部填充为 '.'
        for (int j = 1; j <= 2 * n - 1; j++)
            a[i][j] = '.';         // 空白网格用 '.' 表示

    int x = n;                     // x: 菱形的中心行(同时也是中心列)
    int l = x, r = x;              // l: 当前行菱形左边界列; r: 当前行菱形右边界列

    for (int i = 1; i <= x; i++)  // 绘制菱形的上半部分(含中心行)
    {
        a[i][l] = '+', a[i][r] = '+';  // 在当前行左右边界标记 '+'
        l--, r++;                  // 下一行左边界左移,右边界右移,菱形逐渐变宽
    }

    l = x, r = x;                  // 重置左右边界到中心列

    for (int i = 2 * n - 1; i >= x; i--)  // 绘制菱形的下半部分(含中心行)
    {
        a[i][l] = '+', a[i][r] = '+';  // 在当前行左右边界标记 '+'
        l--, r++;                  // 上一行左边界左移,右边界右移,菱形逐渐变宽
    }

    for (int i = 1; i <= 2 * n - 1; i++)  // 输出画布
    {
        for (int j = 1; j <= 2 * n - 1; j++)
            cout << a[i][j];       // 输出第 i 行第 j 列的字符
        cout << endl;              // 每行输出后换行
    }

    return 0;
}

【运行结果】

4
...+...
..+.+..
.+...+.
+.....+
.+...+.
..+.+..
...+...
posted @ 2026-07-01 14:19  团爸讲算法  阅读(70)  评论(0)    收藏  举报