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

相关文章
|
XML Java 数据格式
如果Spring中有两个ID相同的Bean,会报错吗?
有位粉丝被 问到这样一个问题,说在Spring中,如果有两个ID相同的Bean,会不会报错?如果报错,会在哪个阶段报错? 这个问题也要分析具体的情况,才能完整的回答。我从三个方面来回答你的问题吧。
563 0
|
存储 SQL 关系型数据库
高效访问数据的关键:解析MySQL主键自增长的运作机制!
高效访问数据的关键:解析MySQL主键自增长的运作机制!
392 1
|
NoSQL Linux Redis
Linux系统中安装redis+redis后台启动+常见相关配置
Linux系统中安装redis+redis后台启动+常见相关配置
|
8月前
|
人工智能 开发框架 机器人
AstrBot:轻松将大模型接入QQ、微信等消息平台,打造多功能AI聊天机器人的开发框架,附详细教程
AstrBot 是一个开源的多平台聊天机器人及开发框架,支持多种大语言模型和消息平台,具备多轮对话、语音转文字等功能。
4491 15
AstrBot:轻松将大模型接入QQ、微信等消息平台,打造多功能AI聊天机器人的开发框架,附详细教程
|
前端开发 JavaScript 搜索推荐
打造个人博客网站:从零开始的HTML与CSS之旅
【9月更文挑战第31天】在这个数字时代,拥有一个个人博客网站是展示自我、分享知识和连接世界的重要方式。本文将引导你通过简单的HTML和CSS知识,一步步构建起你的在线空间。无论你是编程新手还是希望通过实践加深理解,这篇文章都将是你的理想指南。我们将探索基本概念,实现页面布局,并点缀以个性化样式,最终将静态页面转变为动态交互式网站。准备好了吗?让我们开始吧!
|
SQL 数据库 流计算
Flink CDC数据读取问题之一致性如何解决
Flink CDC 使用Change Data Capture (CDC)技术从数据库捕获变更事件,并利用Flink的流处理能力确保数据读取一致性。相较于传统工具,它具备全增量一体化数据集成能力,满足实时性需求。在实践中解决了高效数据同步、稳定同步大量表数据等问题。应用场景包括实时数据同步、实时数据集成等。快速上手需学习基本概念与实践操作。未来发展方向包括提升效率与稳定性,并依据用户需求持续优化。
310 1
|
IDE Java 测试技术
Java面试题:什么是Java中的单元测试以及如何编写单元测试?
Java面试题:什么是Java中的单元测试以及如何编写单元测试?
427 1
|
存储 SQL 关系型数据库
【MySQL进阶-03】深入理解mysql的索引分类,覆盖索引,覆盖索引失效,回表,MRR
【MySQL进阶-03】深入理解mysql的索引分类,覆盖索引,覆盖索引失效,回表,MRR
339 0
|
Java
《Java工程师成神之路》电子版
《Java工程师成神之路(基础篇)》介绍了普通Java工程师必须要学习的相关知识点,包括面向对象和Java语言基础两大部分,涵盖基本数据类型、关键字、异常、I/O流、集合、反射、泛型和枚举......
590 0
 《Java工程师成神之路》电子版
|
Java API Apache
Springboot 前后端分离项目使用 POI 生成并导出 Excel
Springboot 前后端分离项目使用 POI 生成并导出 Excel
1797 0
Springboot 前后端分离项目使用 POI 生成并导出 Excel