本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印
*****
***
*
***
*****
所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。
给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。
输入格式:
输入在一行给出1个正整数N(≤1000)和一个符号,中间以空格分隔。
输出格式:
首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。
输入样例:
19 *
输出样例:
*****
***
*
***
*****
2
以下给出参考代码:
#include <stdio.h>
#include <math.h>
int main()
{
int num = 0; /* 字符个数 */
char ch; /* 存放字符 */
int row = 1; /* 表示沙漏的行数 */
int space = 0; /* 表示空格数 */
int i, j; /* 用于循环初值 */
int Row_cal(int x);/* 定义函数,计算总个数 */
/* 输入个数和字符 */
scanf("%d %c", &num, &ch);
if (num <= 0)
return 0; /* 如果输入的数不是正整数,则退出 */
/* 计算row值 */ // Sn = (row+1)*(row+1) / 2 - 1
while (Row_cal(row) <= num)
{
row += 2;
}
row -= 2; /* 还原row值 */
/* 输出沙漏 */
for (i = row; abs(i) <= row; i -= 2) /* 外层循环输出行 */
{
/* 输出空格数 */
space = (row - abs(i)) / 2;
while (space-- != 0)
{
printf("%c", ' ');
}
/* 输出每行字符数 */
for (j = 0; j < abs(i); j++)
{
printf("%c", ch);
}
putchar('\n'); /* 换行 */
if (1 == i)
i = -i;
}
/* 输出剩余字符数 */
printf("%d", num - Row_cal(row));
}
int Row_cal(int x)
{
return (x + 1) * (x + 1) / 2 - 1;
}
这道题的思路就是要计算出最大的沙漏形状,每一行先输出空格,接着输出字符。而这个沙漏有几个特点:
- 行数等于沙漏中字符最多的一行
- 行数必须为奇数
- 上下两对称
如果你无法理解以上代码,那么以下为代码分析:
首先创建一系列变量,为了下面存储各值。接下来我们定义了一个函数Row_cal(x) ,目的是计算 x 行的沙漏字符总数。函数的定义放在了最后。
接下来输入数量和字符分别赋值给变量num和ch.
if (num <= 0)
return 0;
这段代码表示我们需要输入一个正整数。
现在开始计算我们输入的数能输出多少行的沙漏:
while (Row_cal(row) <= num)
{
row += 2;
}int Row_cal(int x)
{
return (x + 1) * (x + 1) / 2 - 1;
}
通过数学的数列知识,可以得到 x 行沙漏得到字符总数的公式为:Sn = (x + 1)² / 2 - 1. 在这里我们使用了一个循环,只要计算后的总数小于等于我们输入的数num,那么我们就从最小值1每次加2,直到 row 行沙漏数大于num. 我们可以发现,无论是 row 行计算后的数量是小于num还是等于 num, 退出循环后得到的 row 值都是比真正的 row 值大2. 所以接下来代码 row -= 2 还原 n 值。
拿到 row 值后,便可以开始输出沙漏了。
for (i = row; abs(i) <= row; i -= 2) /* 外层循环输出行 */
{
/* 输出空格数 */
space = (row - abs(i)) / 2;
while (space-- != 0)
{
printf("%c", ' ');
}/* 输出每行字符数 */
for (j = 0; j < abs(i); j++)
{
printf("%c", ch);
}
putchar('\n'); /* 换行 */if (1 == i)
i = -i;
}
我们定义了二层循环,外层循环来输出行,内层循环输出列。我们知道,行数就等于沙漏最上(下)面一行的字符数。我们首先将 row 值赋给 i , 循环的条件为:i 的绝对值小于 row,每次循环后,i 减 2. 这样 i 的值一直等于每一行的字符数。这样可以输出对应的行数,而当 i 等于1的时候,再减2会变成 -1,沙漏打印的时候并没有-1,而是3个字符 --> 1个字符 --> 3个字符。所以当 i 为1 的时候,我们外层for循环最后使用一个 if()条件语句,当 i 等于 1 时,置换为 -1.
到此我们已经可以输出对应的行数,接下来就是每一行该输出多少字符。首先看空格,第一行不输出空格,第二行输出一个,第三行输出两个……输出一个,不输出。空格也符合回文特性。通过数学知识可以找到每一行空格数刚好与row值有对应关系:space = (row - abs(i)) / 2。所以,我们使用一个while语句在每一行上输出space个空格数,每次循环space要减1,直到为0.
现在开始打印字符,这里很简单,我们知道 i 的绝对值恰好等于每一行的字符数,那么这里直接使用for循环输出 i 个字符,此for循环结束后,换行。
最后不忘了要将剩余字符输出。