文章目录
L1-002 打印沙漏 (20 分)
总结
L1-002 打印沙漏 (20 分)
题目链接:L1-002 打印沙漏
题目:
L1-002 打印沙漏 (20 分)
本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印
所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。
给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。
输入格式:
输入在一行给出1个正整数N(≤1000)和一个符号,中间以空格分隔。
输出格式:
首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。
输入样例:
19 *
输出样例:
本博客给出题目截图:
本题讲解
典型的一道模拟题目,首先我们要明确我们要求什么:一个图 + 一个剩余的数,观察图像的打印规律,第一行打印5个'*',第二行打印1个' '和3个'*',第三行打印2个' '1个'*',剩下的行数就是对称而来,我们为了方便进行计数和观察,在其中加上一行变成如下图所示的模样进行分析:
接下来我们来找规律:我们发现关于'*'的打印来说成一个等差数列,上半部分的话符合(2n - 1,...,5,3,1)的规律,下半部分的话符合(1,3,5,...,2n - 1)的规律,那么总数就可以用等差数列求和公式去计算(高斯求和):上半部分 = 下半部分 = n²,n是行数,那么总数就是2n²,因为我们多加了一行(个)'*'去帮助我们分析题目,所以实际的总数应该是(2 * n * n - 1),我们需要这个值小于等于我们输入的总数,所以求最大n是多少我们可以通过一个循环去求:
for (int i = 1; ; i ++ ) if (2 * i * i - 1 > n) { t = i - 1; //我们要求的是小于等于n的数 //退出循环的时候是正好大于n的第一个值,所以我们小于等于的最大值就是i - 1 break; }
打印上半部分:
int q = t, j = 0, r; for (int i = t; i >= 1; i -- ) { for (int k = 0; k < j; k ++ ) cout << ' '; //j初始化是0,代表第一行不打印空格 j ++; //然后每打印一行让j + 1 r = j; for (int k = 0; k < 2 * i - 1; k ++ ) cout << op; cout << endl; }
注意最后打印的空格数是最后打印完成后 + 1的值,比如例子中,上半部分的最后一行要打印3个空格,那么在打印完成之后j的值即r的值是4,(因为每打印完都要 + 1),所以我们要让r -= 2;,因为我们下半部分的打印相当于是从上半部分的倒数第二行开始打印的,如果不明白为什么要让r -= 2;的话,可以自己模拟一下,就拿例子来说,下半部分第一行打印的时候需要打印2个空格,而我们的r经过上半部分的打印后为4,所以要让r -= 2;
打印下半部分
r -= 2; t = q, j = r; for (int i = 2; i <= t; i ++ ) { for (int k = 0; k < j; k ++ ) cout << ' '; j --; for (int k = 0; k < 2 * i - 1; k ++ ) cout << op; cout << endl; }
最后记得输出res(剩余多少个数)
AC代码:(C++)
#include <iostream> using namespace std; int main() { int n, t; char op; cin >> n >> op; for (int i = 1; ; i ++ ) if (2 * i * i - 1 > n) { t = i - 1; break; } int res = n - (2 * t * t - 1); int q = t, j = 0, r; for (int i = t; i >= 1; i -- ) { for (int k = 0; k < j; k ++ ) cout << ' '; j ++; r = j; for (int k = 0; k < 2 * i - 1; k ++ ) cout << op; cout << endl; } r -= 2; t = q, j = r; for (int i = 2; i <= t; i ++ ) { for (int k = 0; k < j; k ++ ) cout << ' '; j --; for (int k = 0; k < 2 * i - 1; k ++ ) cout << op; cout << endl; } cout << res << endl; return 0; }
通过测试截图:
总结
一道比较基础的模拟题,当初刚开始看的时候确实难为了我好一阵子,现在再看觉得轻松了不少,找到规律后写起来很方便,注意写模拟题之前自己的思路必须十分的清晰,可以先在纸上模拟一下大致流程,写一个伪代码出来,否则写题的过程中很容易搞混一些变量,从而浪费时间.