经典之打印沙漏-数学分析-C/C++

打印沙漏

打印沙漏的这道问题可以说是经典之极,从我学程序设计、到学数据结构、以及后来参加各种程设赛,这道题几乎都必须经历。这道题真正涉及到的代码语法并不难,难的是如何根据给定的一个数字确定能实现的最大沙漏、沙漏行数、沙漏每行的符号数和空格数。初做这道题时想了很久,最后也是暴力求解——“试”出来最大沙漏数、沙漏行数等。但是毕竟学了多年数学,一直觉得一定能有一个数学关系式把最大沙漏、沙漏行数、沙漏每行的符号数和空格数这些变量都给联系起来。

最近在PTA刷题的时候又遇到了这道题,静下心来又分析了一下题目,最终也是终于找到了我要的关系式,因此写这篇文章分享出来。废话不多说,咱们开始。首先老规矩,原题内容如下:

1 题目内容

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

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

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

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

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

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

输入样例:

19 *

输出样例:

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

2 题目分析

题目的输入只有两个变量:符号数量、相应的符号,剩下的内容全靠我们自己分析推导。为了方便起见,我分别用allc两个变量名来表示两个变量。对于这两个变量,第二个变量c只是用来告诉我们输出什么符号,格式的控制完全依靠第一个变量all。想要正确的输出沙漏形状,我们得通过符号数量确定以下内容:

  1. 这些数量的符号所能实现的最大沙漏的符号数量max(核心问题1,基本目标)
  2. 实现最大沙漏后剩余的符号数量surplus
  3. 所能实现的最大沙漏的行数N每行的符号数cha(核心问题2,控制输出格式)
  4. 沙漏每行的空格数spa(核心问题3,居中控制)

有了数据和目标,接下来的任务就是实现这些目标。前面也提到过,上面这些变量我们都可以通过暴力求解法枚举求得。但这毕竟不符合我们对代码高效、简洁的追求。而且,这些变量之间明显存在着数学关系,找到这个数学关系并利用其求解,才更有工科的数学乐趣~下面,我们就利用数学思想,来找出这一关系。

3 数学归纳

为了叙述方便,后面我们的沙漏符号都使用*来表示。首先,我们先来看看对于题目要求沙漏形状的行数和符号数。

3.1 沙漏形状的行数和符号数

对于题目要求的沙漏形状,最小的情况下即为1个符号的情况,即:

*

此时我们有:max = 1N = 1。用n表示我们的第n个沙漏,最小的沙漏即为n = 1,即:

n N max
1 1 1

对于第二个沙漏的情况(n = 2),即为:

***
 *
***

此时我们有:max = 7N = 3。通过观察两个沙漏的变化我们易知,第二个沙漏是在第一个沙漏的最顶端最底端分别加了一行,增加的这两行的符号数 = 原顶端(底端)的符号数 + 2,所以我们有:

n N max
1 1 1
2 3 7 = 1 + 2 * 3

有了前面两组数据,其实第三个沙漏的情况就很好分析了。对于第二个沙漏的情况(n = 3),即为:

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

此时我们有:max = 17 = 1 + 2 * 3 + 2 * 5N = 5 = 1+2+2,即:

n N max
1 1 1
2 3 7 = 1 + 2 * 3
3 5 17 = 1 + 2 * 3 + 2 * 5

通过观察,我们已经很容易得知,对于n = n时,我们有 N = 2n-1max = 1 + 2 * 3 + …… + 2 * (2n - 1)N已经可以表示为一个对任意n都成立含n的表达式了,而max目前的表达式对n= 1不成立,因此结果还不是很显然。此时,我们也可以到此为止,在实现代码时区分n = 1n > 1的情况,但我依然认为找到一个更合适的表达式会更加方便。

因此我们再对max分析,进一步会发现:当n = 1时,max = 1 = 2 * 1 - 1;当n = 2

  • 33
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值