『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语言分享题到此结束,咱们下期再见

相关文章
|
6月前
|
编译器
11.14作业(打印图案,乘法表右对齐,圆周率,哥德巴赫猜想)
11.14作业(打印图案,乘法表右对齐,圆周率,哥德巴赫猜想)
|
6月前
输出字母沙漏
输出字母沙漏
|
2月前
打印出如下图案
打印出如下图案。
27 3
|
5月前
1027 打印沙漏
1027 打印沙漏
|
5月前
|
C语言
C语言-----打印用“*”组成的X形图案,输出一个数表示行数
C语言-----打印用“*”组成的X形图案,输出一个数表示行数
|
6月前
L1-002 打印沙漏
L1-002 打印沙漏
42 0
学C的第二十四天【练习:1. 打印菱形;2. 打印自幂数;3. 求Sn=a+aa..n项之和;4. 喝汽水问题;5. 调整数组使奇数位于偶数前面;6. 打印X形图案;7……;8……;9……;10……】-2
5. 调整数组使奇数全部都位于偶数前面 题目: 输入一个整数数组,实现一个函数, 来调整该数组中数字的顺序使得数组中所有的奇数位于数组的前半部分, 所有偶数位于数组的后半部分。
126 0
圣诞树的打印
圣诞树的打印
100 0
输出三个乘法表,按照完整乘法表、下三角乘法表、上三角乘法表的顺序输出,每个表中间空一行。对于每个乘法表,首行升序输出的 11 到 99 数与数之间恰好有三个空格,接下来 10 行每栏内容都需要
输出三个乘法表,按照完整乘法表、下三角乘法表、上三角乘法表的顺序输出,每个表中间空一行。对于每个乘法表,首行升序输出的 11 到 99 数与数之间恰好有三个空格,接下来 10 行每栏内容都需要
73 0