B4412 [GESP202509 二级] 菱形

· · 题解

欢迎报名洛谷网校,报名课程可以获得对应组别的知识点讲解与答疑服务,期待和大家一起进步!点击图片即可报名。

:::align{center} :::

要解决这类问题,关键在于找出决定一个位置是打印 # 还是 . 的内在规律。我们可以把这个 n \times n 的字符画想象成一个坐标系,每一个位置都有一个行号 i 和一个列号 j。我们的任务就是找到一个通用的数学公式,对于每一个第 i 行第 j 列(下文简称 (i, j)),这个公式能告诉我们应该在此处画什么。

由于题目给定的 n 是一个奇数,所以这个菱形拥有一个完美的中心点。这个中心点的行号和列号都是 (n + 1) / 2。我们可以把这个中心位置记作 mid。现在,让我们观察一下菱形上的所有 # 点与这个中心点 (mid, mid) 的关系。

我们可以计算任意一点 (i, j) 到中心点的“曼哈顿距离”,这个距离的计算方式不是走直线,而是像在城市街区里走路一样,只能横着或竖着走,它的计算公式是 abs(i - mid) + abs(j - mid),其中 abs 表示取绝对值。

:::info[考点提示] abs 函数是明确在 GESP 二级大纲中写出的考点哦。

abs(x) 的意思是,如果 x\geq 0,那么还是 x。否则,如果 x<0,那么就是 -x。在数学语言中,abs(x) 写作 $ x $。

通过对样例的观察和计算,我们可以发现一个非常优美的规律:所有构成菱形边界的 # 点,它们到中心点的曼哈顿距离都恰好等于 mid - 1。例如,对于一个 5\times 5 的菱形,中心点是 (3, 3)mid - 1 就是 2。第一行的 #(1, 3),它到中心的距离是 |1-3| + |3-3| = 2+0 = 2;第二行的 #(2, 2),距离是 |2-3| + |2-3| = 1+1 = 2。所有 # 点都满足这个条件。

找到了这个规律后,程序就变得非常简单了。我们只需要用两层嵌套的循环来遍历从 (1, 1)(n, n) 的每一个坐标点。在循环内部,我们计算当前点 (i, j) 到中心点的曼哈顿距离,并判断它是否等于 mid - 1。如果等于,就输出 #;如果不等,就输出 .。每当内层循环(即一行)结束时,我们输出一个换行符,这样就能绘制出完整的菱形了。

参考代码:

for (________) {
    for (________) { // 二重循环,遍历 (1, 1) 到 (n, n) 的每一个坐标点
        if (________) // 计算到中心点的曼哈顿距离是否符合条件
            cout << '#';
        else
            cout << '.';
    }
    ________;
}