1.题目描述
自测-1 打印沙漏 (20分)
本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印
所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。
给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。
输入格式:
输入在一行给出1个正整数N(≤1000)和一个符号,中间以空格分隔。
输出格式:
首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。
输入样例:
19 *
输出样例:
2.我的解题思路
- 首先,写出根据行数计算“沙漏”需要用到的符号数目,这里我采用递归的方式实现,从题目示例中很容易看出,“沙漏”符号数目每次相对于上一次增加2*n个符号,其中n代表行数。示例代码如下:
int count(int n)
{
if (n == 1){
return 1;
} else {
if(n % 2 == 0){
n = n - 1;
}
return count(n - 2) + n * 2;
}
}
特别说明:从题目可知,行数为奇数,每行符号数目也为奇数,所以每次递减都是-2。
- 计算行号,这里用flag表示,确定flag需要用到count函数,当输入符号数N处于count(n - 1)和count(n)之间时,flag=n - 1;同样由于行数时奇数,所以从1开始递增,每次增加2,即flag=n-2;示例代码如下:
for(i = 1; i <= 33; i = i + 2){
if(N == 1){
num = count(1);
flag = 1;
break;
}
if(N >= ((i - 2) * (i - 2)) && N < i * i){
if(N > count((i - 2)) && N < count(i)){
num = count((i - 2));
flag = i - 2;
} else {
num = count(i);
flag = i;
}
}
}
if(flag != 1 && N - num > flag * 2){
for(t = flag; t <= 45; t = t + 2){
if(N > count((t - 2)) && N < count(t)){
num = count((t - 2));
flag = t - 2;
break;
}
}
}
特别说明:num用于记录需要的符号数,因为最后需要打印有多少符号没有使用,即需要打印N-num。
我最开始写的时候没有最下面的if块,导致最大值计算错误。最开始计算思路为:打印格式为方阵,那么符号数目应该在两个相邻flag^2之间,但是二次方增加很快,其中会剩余大部分的符号数目没有使用,不符合题目要求。这也是为什么上一个for循环的终止点在33,因为33^2已经超过题目要求的1000了。
后面的if语句首先判断此时的flag是否能够再添加两层,如果可以,说明此时“沙漏”还不是最大,需要继续判断。里面的for循环用于寻找最大“沙漏”,临界点45是利用count函数计算出来的,此时“沙漏”需要的符号数目正好超过最大值1000,所以取该节点。通过count函数不断对比,找出正确的num和flag。
- 打印“沙漏”,逐行打印沙漏,首位两行符号数目与flag层数相同,逻辑简单,可以直接if选择出来打印,每打印一行沙漏都需要一个换行符。然后是上半部分沙漏,逐层递减,根据层数增加,左右各向中间缩进,例如:首行是第0行,全部打印;第1行需要从1开始打印符号,前面的打印空格,尾部打印到flag-j处为止。示例代码如下:
for(j = 0; j < flag; j++){
if(j == 0 || j == (flag - 1)){
for(k = 0; k < flag; k++){
printf("%c", c);
}
printf("\n");
} else {
if(j <= ceil(flag / 2)){
for(k = 0; k < (flag - j) ; k++){
if(k < j){
printf(" ");
} else {
printf("%c", c);
}
}
printf("\n");
} else {
for(k = 0; k <= j; k++){
if(k < (flag - 1 - j)){
printf(" ");
} else {
printf("%c", c);
}
}
printf("\n");
}
}
}
printf("%d", (N - num));
特别说明:最开始提交,一直提示格式错误。后面看了网上其他人的代码发现,沙漏的右半部分并不是打印的空格,到了后面就结束了。红框标出部分不是空格,直接换行了,经过修改,有了上面的代码。
参考链接
最后寄语
写这篇博客,只是记录下自己解题的过程,可能解法缺陷很大,由于代码完成比较仓促,看起来也不是简洁,有很多重复代码。所以附上别人的解题思路给大家参考。最后,一家之言,欢迎拍砖。