每日编程中遇到任何疑问、意见、建议请公众号留言或直接撩Q474356284(备注每日编程)
本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印
*****
***
*
***
*****
所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。
给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。
输入格式:
输入在一行给出1个正整数N(≤1000)和一个符号,中间以空格分隔。
输出格式:
首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。
输入样例:
19 *
输出样例:
*****
***
*
***
*****
2
解决方法:
(1)算法的基本思想:
这道题看似简单,初看却无从下手。
思路:①计算需要打印的行数 ②打印沙漏
从奇数 1 开始,一直往后 3 ,5 , 7,……,2 i -1。
sum求和,直到sum > N ,记录相加的次数 w,即需要打印的行数为 w(上半部分),全部行数则为 2 * w - 1,因为 “ * ” 为一个的时候只需打印一次,同时记录最大的奇数 j (第一行 “ * ” 的个数)。
因为for循环中多计算了一次sum += (2 * i),才不满足sum <= N,跳出循环,故最后计算剩下的 “ * ” 的个数res 时须加上最后一次加上的 2 * i;
打印沙漏:
注意到:若打印N = 17,每一行前面空格的规律是:0,1,2,2,1,0
“ * ”的个数规律是:5,3,1,3,5.
令 t 为前者的计数器,从 0 开始递增,步长为 1 。
j 为后者的计数器,j 从最大的 5开始递减,步长为 2,当减小到负数时, t 开始递减,步长为 1,j == -1时,跳过(因为一个 “ * ” 只打印一次),j 的取值规律是 5,3,1,-1(跳过),-3,-5。使用for循环打印 “ * ” 时取绝对值即可。
(2)代码实现:
一航写出的:
#include
using namespace std;
//灰灰考研@一航代码
/*
思路:①计算沙漏的行数 ②打印沙漏
*/
int main(){
int N;
char x;
cin >> N >> x;
int w = -1, j;
int sum = -1;
for (int i = 1; sum <= N;i+=2){
w++;
j = i - 2;
sum += (2 * i);
}
int res = N - sum + 2 * (j+2);
int t = 0;
//w是行数,j是最大奇数
for (int m = 1; m <= w * 2 - 1; m++, j -= 2)
{
if (j >= 1){
t++;
}
else
{
t--;
if(j == -1)
j -= 2;
}
for (int k = 1; k <= t - 1; k++)
{
cout <' ';
}
for (int k = 1; k <= abs(j); k++)
{
cout < }
cout <endl;
}
cout < system("pause");
return 0;
}
大牛精简的:
//灰灰考研@一航代码
#include
#define ABS(X) ((X) >= 0 ? (X) : -(X))
int main(){
char c;
int N, M;
scanf("%d %c", &N, &c);
//利用前n项求和公式记录需打印的行数
//1,3,5,7,……,2n-1.Sn = n*n,沙漏总需2n*n-1个“*”
for (M = 1; 2 * M * M - 1 <= N; M++)
;
M--;//判断时多加了一次,此处M即为行数的一半
//总行数为2 * M - 1 行
for (int i = 0; i 2 * M - 1; i++)
{
//第M - 1行是打印一个“*”的那一行
for (int j = 0; j 1 - ABS(M - 1 - i); j++)
putchar(' ');
for (int j = 0; j 2 * ABS(M - 1 - i) + 1; j++)
putchar(c);
putchar('\n');
}
printf("%d", N - 2 * M * M + 1);
return 0;
}
明日预告:人口普查
某城镇进行人口普查,得到了全体居民的生日。现请你写个程序,找出镇上最年长和最年轻的人。
这里确保每个输入的日期都是合法的,但不一定是合理的——假设已知镇上没有超过 200 岁的老人,而今天是 2014 年 9 月 6 日,所以超过 200 岁的生日和未出生的生日都是不合理的,应该被过滤掉。
输入格式:
输入在第一行给出正整数 N,取值在(0,105];随后 N 行,每行给出 1 个人的姓名(由不超过 5 个英文字母组成的字符串)、以及按 yyyy/mm/dd
(即年/月/日)格式给出的生日。题目保证最年长和最年轻的人没有并列。
输出格式:
在一行中顺序输出有效生日的个数、最年长人和最年轻人的姓名,其间以空格分隔。
输入样例:
5
John 2001/05/12
Tom 1814/09/06
Ann 2121/01/30
James 1814/09/05
Steve 1967/11/20
输出样例:
3 Tom John