打印沙漏

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));

特别说明:最开始提交,一直提示格式错误。后面看了网上其他人的代码发现,沙漏的右半部分并不是打印的空格,到了后面就结束了。红框标出部分不是空格,直接换行了,经过修改,有了上面的代码。
这里写图片描述

参考链接

题目链接
解题参考
解题参考2

最后寄语

写这篇博客,只是记录下自己解题的过程,可能解法缺陷很大,由于代码完成比较仓促,看起来也不是简洁,有很多重复代码。所以附上别人的解题思路给大家参考。最后,一家之言,欢迎拍砖

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值