1027 打印沙漏 (20 分)
本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印
*****
***
*
***
*****
所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。
给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。
输入格式:
输入在一行给出1个正整数N ( ≤ 1000 ) (≤1000) (≤1000)和一个符号,中间以空格分隔。
输出格式:
首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。
输入样例:
19 *
输出样例:
*****
***
*
***
*****
2
解题思路
- 首先要算出能形成的最大沙漏的行数
-
由于沙漏可以看成两个顶端重合的三角形,可用等差数列前 n n n项和公式求得一个三角组成符号数量
s u m sum sum
和行数l l l
关系满足以下l + l ( l − 1 ) = s u m l + l(l - 1) = sum l+l(l−1)=sum
即
l 2 = s u m l^2 = sum l2=sum
则沙漏的组成符号数量为
2 l 2 − 1 = s u m 2l^2 - 1 = sum 2l2−1=sum
-
可以知道组成沙漏的符号数量只能比总数量
n n n
少,不能多,那么我们可以得到的最大行数与符号总数关系为( ⌊ ⌋ \lfloor\rfloor ⌊⌋ 为向下取整)⌊ n + 1 2 ⌋ = l \lfloor\sqrt{\cfrac{n + 1}{2}}\rfloor = l ⌊2n+1⌋=l
-
- 将沙漏图案分为上下两部分,每一部分又分为空格部分和符号部分
- 上半部分看作是一个倒三角,循环将每一层要输出的图案插入至字符串中
- 将倒三角的第一层
i
i
i 标为
0
0
0,那么可以得到每一行的数量关系
i = n u m o f ( s p a c e ) i = numof(space) i=numof(space)
2 ( l − i ) − 1 = n u m o f ( c h ) 2(l - i) - 1 = numof(ch) 2(l−i)−1=numof(ch)
- 将倒三角的第一层
i
i
i 标为
0
0
0,那么可以得到每一行的数量关系
- 将下半部分看作一个没有顶点符号的正三角,将每一层的图案插到字符串中
- 将三角的第一层标为
0
0
0,那么得到数量关系为
l − i − 1 = n u m o f ( s p a c e ) l - i - 1 = numof(space) l−i−1=numof(space)
2 i + 1 = n u m o f ( c h ) 2i + 1 = numof(ch) 2i+1=numof(ch) - 在写的时候可以先将顶点算入三角形内,确认输出成功后再将第一行去掉
- 将三角的第一层标为
0
0
0,那么得到数量关系为
- 上半部分看作是一个倒三角,循环将每一层要输出的图案插入至字符串中
- 最后输出 n − s u m n - sum n−sum
AC代码
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int n;
char ch;
cin >> n >> ch;
int l = sqrt((n + 1) / 2), sum = l * l * 2 - 1;
for (int i = 0; i < l; ++i)
{
string temp;
temp.append(i, ' ');
temp.append(2 * (l - i) - 1, ch);
cout << temp << endl;
}
for (int i = 1; i < l; ++i)
{
string temp;
temp.append(l - i - 1, ' ');
temp.append(2 * i + 1, ch);
cout << temp << endl;
}
cout << n - sum << endl;
return 0;
}