1027 打印沙漏——20分

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

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

所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大
顺序递增;首尾符号数相等。给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。

输入格式

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

输出格式

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

输入样例:

19 *

输出样例:

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

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

思路:
①这道题需要用等差数列的知识来推导对要打印的层数,然后再进行输出和剩余字符的计算
②除去中间的单个字符,图形上下是对称的,只看下半部分的话(有a1=3,a2=5,a3=7...),所以层号和每层的字符数之间的关系为an=2n+1
③由a1=3,an=2n+1,根据等差数列前N项和公式Sn=n(a1+an)/2求得此问题中上下两个对称层的Sna=n(n+2)
所以全部字符的数量为2S(n-1)+1=2×n^2-1,但是n并不是层数,真正的层数是2n-1
④推导过程可参考下图,建议大家可以在草稿纸上画个图形对着进行推导,这样更加直观:

a1=3,a2=5,a3=7,a4=9......,an=2n+1
Sna=n(n+2)   //除中间一个字符外的上或下半边字符数量的前n项和公式
↓↓↓↓↓↓↓↓↓↓
b1=1+2×0
b2=1+2×3
b3=1+2×(3+5)
b4=1+2×(3+5+7)
......
bn = 1+2×(a1+a2+a3+...+a(n-1)) = 1+2S(n-1)a = 2×n^2-1   //图形中全部字符的数量和半边层数n的关系式
//n在b中所指的半边的层数包括了中间一层,因为bn最小是从1开始的,所以全部的层数为2n-1层

⑤根据公式bn求出可以达到的最大层数,条件是bn不能大于题目中的N(可以使用的字符数量),见代码部分的7~10行,然后求出剩余没用掉的字符数量,剩下的图形输出部分就并不难了

代码:

#include<bits/stdtr1c++.h>
using namespace std;
int main() {
	int sum;
	char c;
	scanf("%d %c", &sum, &c);
	int h = 1;
	while (2 * h * h - 1 <= sum) h++;  //根据公式写出条件来判断出半边的层数
	h -= 1;
	int len = 2 * h - 1;  //len为一共有多少层
	int surplus = sum - (2 * h * h - 1); //计算出剩下的字符数量
	int up_len = len / 2 + 1, down_len = len / 2;  //分别求出上半部分和下半部分的层数
	for (int i = up_len, j = 0; i >= 1; i--, j++) {
		for (int k = 0; k < j; k++) printf(" ");
		for (int k = 0; k < i * 2 - 1; k++) printf("%c", c);
		cout << endl;
	}  //打印上半层(包括中间一点)
	for (int i = 2, j = down_len - 1; i <= down_len + 1; i++, j--) {
		for (int k = 0; k < j; k++) printf(" ");
		for (int k = 0; k < i * 2 - 1; k++) printf("%c", c);
		cout << endl;
	}  //打印下半层
	cout << surplus; //输出剩余的字符数量
	return 0;
}
posted @ 2022-08-10 01:22  Fare-Well  阅读(54)  评论(0)    收藏  举报