PTA编程打印空心字符菱形

本题目要求读入菱形起始字母和菱形的高度,然后输出空心字符菱形。所谓“空心菱形”是指:每行由两端为字母、中间为空格的字符串构成,每行的字符串中心对齐;上半部分相邻两行字符串长度差2,且字母从给定的起始字母逐一递增;下半部分与上半部分对称。
输入格式:
输入在一行中给出起始字母(范围为英文大写字母A-G)和菱形的高度(为不超过10的奇数)。
输出格式:
输出空心字符菱形。
输入样例:


B 5

输出样例:

  B
 C C
D   D
 C C
  B

代码长度限制 16 KB
时间限制 400 ms
内存限制 64 MB

      • 1.曼哈顿距离
      • 2.样例分析
      • 3.思路形成
      • 4.判断字母
      • 5.判断空格
      • 6.完整答案

1.曼哈顿距离

在讲解本题之前,先引入本题用到的非常重要的数学知识——曼哈顿距离。曼哈顿距离是通过沿坐标轴的网格线移动来测量两点之间的距离,只能水平和垂直方向移动,而不能斜向移动。可以用数学公式表示为:

d = ∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ d = ∣x_1 − x_2∣ + ∣y_1 − y_2∣ d=x1x2+y1y2

若在平面内存在两点(x1, y1)和(x2, y2),d即为两点的曼哈顿距离。

2.样例分析

以n = 5为例,通过上述引入的曼哈顿距离(以下简称距离d)可知,本题首先需要确认基点,其余点均可求出距离。因为菱形是高度对称的图形,我们不妨设中心点为距离的基点。距离如下图所示:
1700224773711.pngimage.png
通过对比两图,我们不难发现出现字母的位置均为距离d为2的位置。因此我们可以猜测,出现字母的位置距离d唯一且相等。(多次改变n的值,得到的结果均是如此)

3.思路形成

因为n = 5,而距离d又是2,可以猜测n与距离d的关系

int d = (n + 1) / 2 - 1;

因为距离d是横纵坐标之间的距离,我们不妨将此菱形放在直角坐标系中,左上角的坐标为(1, 1)
基点位于菱形中心,所以坐标为(3, 3),因此可以通过n值表示基点坐标:

int cx = (n + 1) / 2;
int cy = (n + 1) / 2;

确定基点坐标后,可以通过嵌套循环来遍历每个位置,将循环中的变量当做每个位置x,y的值。

for (int i = 1; i <= n; i ++)
{
    for (int j = 1; j <= n; j ++)
    {

    }
}

4.判断字母

出现字母处的情况比较简单,因此先判断出现字母的位置,由上述分析可知,当距离等于d时出现字母

if (abs(i - cx) + abs(j - cy) == d)
    printf("%c", a);

由题意可知上半段字母递增,下半段字母递减。因此还需额外进行判断:
n = 5时,前3行递增(注意只增了两次),可得行数与n的关系

if (i < (n + 1) / 2) //此处不能有等号
    a += 1;
else
    a -= 1;

5.判断空格

判断空格较为复杂,因为只有左半边外侧出现了空格。下面列举一种典型的错误写法:

if (abs(i - cx) + abs(j - cy) != d)
    printf(" ");

该写法判断时忽略了左右区别,会导致右半边也出现空格。
空格在小于字母距离d的位置一定会出现,因此可以先考虑这种简单情况

if (abs(i - cx) + abs(j - cy) < d)
    printf(" ");

想要让左侧出现空格而右侧没有,就要对横坐标 j 进行限制,当 j <= (n + 1) / 2 即可表示左半边。因此:

if (abs(i - cx) + abs(j - cy) > d && j <= (n + 1) / 2)
        printf(" ");

合并可写为:

if (abs(i - cx) + abs(j - cy) > d && j <= (n + 1) / 2 || abs(i - cx) + abs(j - cy) < d)
        printf(" ");

6.完整答案

#include <stdio.h>
#include <math.h>
int main()
{
    int n;
    char a;
    scanf("\n%c%d", &a, &n);
    int d = (n + 1) / 2 - 1;
    int cx = (n + 1) / 2, cy = (n + 1) / 2;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (abs(i - cx) + abs(j - cy) == d)
                printf("%c", a);
            if (abs(i - cx) + abs(j - cy) > d && j <= (n + 1) / 2 || abs(i - cx) + abs(j - cy) < d)
                printf(" ");
        }
        if (i < (n + 1) / 2)
            a += 1;
        else
            a -= 1;
        printf("\n");
    }
    return 0;
}
  • 36
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

比奇堡碌碌无为比目鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值