『C/C++』Eg5: 打印沙漏

简介: 『C/C++』Eg5: 打印沙漏

本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印

*****
 ***
  *
 ***
*****

所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。

给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。

输入格式:

输入在一行给出1个正整数N(≤1000)和一个符号,中间以空格分隔。

输出格式:

首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。

输入样例:

19 *

输出样例:

*****
 ***
  *
 ***
*****
2

题解:

想必很多小伙伴刚开始看到这个题目的时候觉得这题很简单,上手很容易,但是当真正思考做起来的时候,发现还是有点无从下手的。所以我现在就讲解一下这题我的思路和解法~

第一部分 分解

首先这个“沙漏”是上下对称的,我们可以先找中间以上有几层(包括中间那一层),找到之后上面的层数之后减一,就是下面的层数。

我们用总数相减法来求上面的层数:

除了第一次(也就是减去中间)是一个,其他都是减去2*i,每减一次,都需要计数。一直往下减,直到x为负数,计数停止。

比如:14 *

这里x为14,第一次x=14-1=13;count=1;

第二次x=13-2x3=7;count=2;

第三次x=7-2x5=-3<0

跳出循环,因为count为2,所以上面有两层。

由于减去第一层和减去多层少个二倍,所以将一层和多层单独来写。

由此思路,代码如下:

int Count(int x)
{
    int flag = 1, count = 1, i = 3;
    if (x < 7)//一层
        return 1;
    else//多层
    {
        x -= 1;//先减去中间层
        while (flag)
        {
            x -= 2 * i;
            if (x >= 0)
            {
                flag = 1;
                count++;
            }
            else
                flag = 0;
            i += 2;
        }
    }
    return count;
}

这里就将上面的层数count求出来了,下面的层数就是count-1;


第二部分:打印

上半面

这里找到层数后,就开始考虑打印了。

打印分为空格和*。这里我用表格来显示各部分各部分之间的联系。

由于只需要打印每一层 * 之前的空格就可以,

表格如下 :

for(j=0;j<count;j++) 空格个数
j=0 0
j=1 1
j=2 2
j=n n

所以打印空格的代码如下:

for (i = 0; i < count; i++)
{
    for (j = 0; j < i; j++)
        printf(" ");
}

现在我们来考虑打印*的部分,还是老样子,表格如下:

for(j=0;j<count;j++) * 的个数
j=0 2*count-1
j=1 2*(count-1)-1
j=2 2*(count-2)-1
j=n 2*(count-j)-1

所以代码如下:

int k = count;
for (i = 0; i < count; i++)
{
    for (j = 0; j < 2 * k - 1; j++)
    {
        printf("%c", c);
    }
    k--;
}

好的,到此,沙漏的上半部分就完成了~


下半面

老样子,咱还是先看空格部分,如下图所示

这里我们可以用数学公式,来求出第一层的空格数,下面每一层的空格则只需根据上一层的空格数-1即可。

求第一层的空格数:

第一层空格数=(用最后一层‘ * ’个数-第一层‘ * ’个数)/2

怎么求最后一层‘ * ‘个数呢,用刚刚上面的公式:2*count-1

所以打印空格代码如下:

int l=0;
l = count * 2 - 1;
l = (l - 3) / 2;
for (i = 0; i < count - 1; i++)
{
    for (j = 0; j < l; j++)
        printf(" ");
    l -= 1;
}

好,打印完下半面空格数,我们来打印下半面的*。这里就很简单,由于第一层的*的个数是3,不变,下一层只需要在原有基础上加2。

所以打印‘ * ’代码如下:

int n = 3;
for (i = 0; i < count - 1; i++)
{
    for (j = 0; j < n; j++)
    {
        printf("%c", c);
    }
    n += 2;
}

到此打印就完成了,现在就差输出剩下没用掉的符号数~


输出未用符号数

只需要在打印函数里,对每一次打印*时进行计数即可。

int Printc(int count, char c)
{
    int count1 = 0;
    for (i = 0; i < count; i++)
    {
        for (j = 0; j < 2 * k - 1; j++)
        {
            printf("%c", c);
            count1++;
        }
    }
    for (i = 0; i < count - 1; i++)
    {
        for (j = 0; j < n; j++)
        {
            printf("%c", c);
            count1++;
        }
    }
}

总代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int Count(int x)
{
    int flag = 1, count = 1, i = 3;
    if (x < 7)
        return 1;
    else
    {
        x -= 1;
        while (flag)
        {
            x -= 2 * i;
            if (x >= 0)
            {
                flag = 1;
                count++;
            }
            else
                flag = 0;
            i += 2;
        }
    }
    return count;
}
int Printc(int count,char c)
{
    int i = 0, j = 0, k = 0, l = 0, n = 3;
    int count1 = 0;
    l = count * 2 - 1;
    l = (l - 3) / 2;
    k = count;
    for (i = 0; i < count; i++)
    {
        for (j = 0; j < i; j++)
            printf(" ");
        for (j = 0; j < 2 * k - 1; j++)
        {
            printf("%c", c);
            count1++;
        }
        printf("\n");
        k--;
    }
    for (i = 0; i < count - 1; i++)
    {
        for (j = 0; j < l; j++)
            printf(" ");
        for (j = 0; j < n; j++)
        {
            printf("%c", c);
            count1++;
        }
        printf("\n");
        l -= 1;
        n += 2;
    }
    return count1;
}
int main()
{
    int x = 0, y = 0;
    char c = 'a';
    scanf("%d %c", &x, &c);
    y = Count(x);
    int F=Printc(y,c);
    printf("%d\n", x-F);
    return 0;
}

方法二:

#include<stdio.h>
void Print(int line, char c)
{
  int i = 0, j = 0, k = 0, count = line;
  //打印上层
  for (i = 0; i < line; i++)
  {
    for (j = 0; j < i; j++)
      printf(" ");
    for (k = 0; k < 2 * count - 1; k++)
      printf("%c", c);
    count--;      
    printf("\n");
  }
  //打印下层
  count = 1;
  for (i = 0; i < line - 1; i++)
  {
    for (j = 1; j < line - i - 1; j++)
      printf(" ");
    for (k = 0; k < 2 * count + 1; k++)
      printf("%c", c);
    count++;
    printf("\n");
  }
}
void Count(int* x,int* y)
{
  int n = 0;
  for (n = 1; 2 * n * n - 1 < *x; n++);
  *y = *x - 2 * (n - 1) * (n-1)+1;
  *x = n - 1;
}
int main()
{
  int x = 0, y = 0;
  char c ;
  scanf("%d %c", &x, &c);
  Count(&x, &y);
  Print(x, c);
  printf("%d", y);
  return 0;
}

好啦~今天C语言分享题到此结束,咱们下期再见

相关文章
|
7月前
|
C++
【PTA】​L1-002 打印沙漏 ​ (C++)
【PTA】​L1-002 打印沙漏 ​ (C++)
81 0
【PTA】​L1-002 打印沙漏 ​ (C++)
|
7月前
|
编译器
11.14作业(打印图案,乘法表右对齐,圆周率,哥德巴赫猜想)
11.14作业(打印图案,乘法表右对齐,圆周率,哥德巴赫猜想)
|
7月前
输出字母沙漏
输出字母沙漏
|
2月前
|
人工智能
打印出杨辉三角形
打印出杨辉三角形。
73 17
|
6月前
1027 打印沙漏
1027 打印沙漏
|
7月前
23.输出正/反九九乘法表
23.输出正/反九九乘法表
39 2
|
7月前
|
弹性计算 运维 Shell
打印9*9 乘法表
【4月更文挑战第29天】
56 1
|
7月前
L1-002 打印沙漏
L1-002 打印沙漏
51 0
|
C语言
C语言:打印用 * 组成的带空格直角三角形图案
思路: 总体思路: 找到规律: 行数 + 列数 < 三角形长度 - 1 打印 两个空格(题目要求带空格的三角形) 其它情况下打印 *号和空格(题目要求带空格的三角形) 使用 while循环 进行多组输入
310 0
输出三个乘法表,按照完整乘法表、下三角乘法表、上三角乘法表的顺序输出,每个表中间空一行。对于每个乘法表,首行升序输出的 11 到 99 数与数之间恰好有三个空格,接下来 10 行每栏内容都需要
输出三个乘法表,按照完整乘法表、下三角乘法表、上三角乘法表的顺序输出,每个表中间空一行。对于每个乘法表,首行升序输出的 11 到 99 数与数之间恰好有三个空格,接下来 10 行每栏内容都需要
82 0