本题要求按照规定格式打印前n行杨辉三角_【每日编程256期】打印沙漏

1027 打印沙漏

每日编程中遇到任何疑问、意见、建议请公众号留言或直接撩Q474356284(备注每日编程)

本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印

*****
***
 *
***
*****

所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。

给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。

输入格式:

输入在一行给出1个正整数N(≤1000)和一个符号,中间以空格分隔。

输出格式:

首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。

输入样例:

19 *

输出样例:

*****
***
 *
***
*****
2
b1639f361150c0702755b529db638015.gif
解决方法:

(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
b99039e61a8121a72a31992b5ea04c21.png
2003290b753bf55b06dc361c0754b494.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值