C语言PAT刷题 - 1027 打印沙漏

作者的话:若有朋友复制代码去PAT试着运行遇到问题的:
1.可能是格式问题,可以先把从本站复制的代码粘贴到记事本,再把记事本里的代码复制,然后粘贴到PAT的代码区,提交本题回答,应该就可以了;
2.可能是注释原因,PAT有时候检测到注释会编译错误,所以可以先把注释删了,再进行提交回答;
3.可能是作者当初根据题目写出来的代码仍存在一些疏漏,而恰好当时的测试机制没那么完善,没检测出问题。后面测试机制有所更新,故出现问题,若有相关需要的可以评论区留言或私信作者,我看到的话会去再查一下疏漏之处,然后更新文章。

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

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

所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。
给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。
输入格式:
输入在一行给出1个正整数N(≤1000)和一个符号,中间以空格分隔。
输出格式:
首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。
输入样例:
19 *
输出样例:

*****
 ***
  *
 ***
*****
2

二、解题思路
读题:

接收一个正整数n(n<=1000)和字符c,表示有n个c。程序根据字符c的数量,以题目所给格式打印出n个c能组成的最大沙漏形状。并在最后一行输出剩下没用掉的字符的个数。
由观察可得,沙漏若以只有1个字符的那一行为对称轴,上下对称,即上下对应行的字符数都是相等的。所以在输出沙漏时可以简化成两部分,只要把沙漏的上半部分输出出来,下半部分只要反一下即可。
只看沙漏下半部分,把单符号行也算进来,则可知第1行是1个符号,第2行比第1行多2个符号,是3个符号,以此类推,分别是1 3 5 7 … (2i-1)(i表示第i行)。后面写代码的时候只需要设置循环,以i为循环变量,然后一行行累加直到总符号数sum>n,说明字符不足以输出第i行。然后从i-1行到第1行,再从第1行到第i-1行,便是能打印的最大沙漏。最后以(2i-1) (2i-3) … 3 1 3 … (2i-3) (2i-1)的格式划分行号,上层第i行与下层第i行相对应,上下第1行为同一行。
继续观察,会发现每行除了符号外还有空格,最大行无空格,后面每往里1行,便多1个空格,可以在按行输出内容的循环内部嵌套一个循环来输出空格。
思路:
1.定义需要的变量,接收数据;
2.设置循环计算n个字符能输出的最大漏斗的最大行号;
3.后面i要做循环变量,所以把最大行号存储到n中,且计算剩下的符号数存储到sum中,方便后面打印;
4.设置两个循环分别打印沙漏的上半部分和下半部分(两个循环大致相同,稍作修改即可);
5.打印剩下的符号数。

三、具体实现
0.标准C源程序框架

#include <stdio.h>
int main()
{
    return 0;
}

1.定义需要的变量,接收数据;

	int n;
	char c;
	int i = 0, j = 0, k = 0, sum = 1;//因为n是正整数,n至少为1,则沙漏至少有一行,
	//则sum直接从第一行的符号数开始累加,后面检测行号时,也不必再检测第一行
	scanf("%d %c", &n, &c, &c);//接收数据,以空格相隔

2.设置循环计算n个字符能输出的最大漏斗的最大行号;

	//1 3 5 7 9 …… 2i-1 - 下半部分,每行符号数量的变化规律
	//2i-1 2i-3 …… 3 1(上半部分和下半部分的1是重复的) - 下半部分,每行符号数量的变化规律
	//可以设置循环一层层拓展,当sum>n时,循环结束,按sum<n的最大值情况下的规格打印每行的空格和符号
	i表示目前准备加的新层的层号。如要加第二层,新层要用的符号数为2*(2*2-1)=6
	for(i=2;(sum+2*(2*i-1))<=n;i++)
	{
		sum += 2 * (2 * i - 1);//计算出目前布置的沙漏总共要用到多少符号
	}

3.后面i要做循环变量,所以把最大行号存储到n中,且计算剩下的符号数存储到sum中,方便后面打印;

	//此时循环结束,最后一次判断符号数足够添加新层的层号是i-1(最后一次判断通过后,加了新层,i++。
	//再进行判断,判断失败,不足以添加新层,所以此时i比最高可添加层号大1)
	//因为后面要循环打印各层,先从最大层号打印到1层,后又要从1层打印到最大层号。
	//所以要使用n记住i的最大层号
	sum=n-sum;//存储不足以组成沙漏新层的符号的数量
    n = i - 1;//存储最大行号

4.设置两个循环分别打印沙漏的上半部分和下半部分(两个循环大致相同,稍作修改即可);

	for (i = i - 1; i >= 1; i--)//i从最大层开始打印,一直打印到第1行,把整个上半部分打印完成
	{
		j = n - i;//计算本行空格数(每行都不一样,所以每轮循环都要计算一遍)
		while (j--)	printf(" ");//每小一层,符号序列前面要多一个空格
		k = 2 * i - 1;//当前行要输出的符号数
		while (k--) printf("%c",c);
		printf("\n");
	}
	for (i = 2; i <= n; i++)//i从2层开始打印
	{
		j = n - i;
		while (j--)	printf(" ");//每小一层,符号序列前面要多一个空格
		k = 2 * i - 1;
		while (k--) printf("%c", c);
		printf("\n");
	}

5.打印剩下的符号数。

	printf("%d",sum);

四、测试数据
写的时候看题目说中心对称一直以为空格也是,然后在每一行的前面加了多少空格,在输出完当行的符号后,继续输出多少个空格,测试点1、2能过去,但是测试点0、3一直显示格式错误。后来查了网上大佬的资料才知道是空格的问题。这一点大家在写这道题的时候也一定要格外注意。
输出符号前有空格,符号后没空格;(测试点0、3)
五、全部代码

#include <stdio.h>
int main()
{
	int n;
	char c;
	int i = 0, j = 0, k = 0, sum = 1;//因为n是正整数,n至少为1,则沙漏至少有一行,则sum直接从第一行的符号数开始累加,后面检测行号时,也不必再检测第一行
	scanf("%d %c", &n, &c, &c);//接收数据,以空格相隔
	//1 3 5 7 9 …… 2i-1 - 下半部分,每行符号数量的变化规律
	//2i-1 2i-3 …… 3 1(上半部分和下半部分的1是重复的) - 下半部分,每行符号数量的变化规律
	//可以设置循环一层层拓展,当sum>n时,循环结束,按sum<n的最大值情况下的规格打印每行的空格和符号
	for(i=2;(sum+2*(2*i-1))<=n;i++)//i表示目前准备加的新层的层号。如要加第二层,新层要用的符号数为2*(2*2-1)=6
	{
		sum += 2 * (2 * i - 1);//计算出目前布置的沙漏总共要用到多少符号
	}
	//此时循环结束,最后一次判断符号数足够添加新层的层号是i-1(最后一次判断通过后,加了新层,i++。再进行判断,判断失败,不足以添加新层,所以此时i比最高可添加层号大1)
	//因为后面要循环打印各层,先从最大层号打印到1层,后又要从1层打印到最大层号。所以要使用n记住i的最大层号
	sum=n-sum;//存储不足以组成沙漏新层的符号的数量
    n = i - 1;//存储最大行号
	for (i = i - 1; i >= 1; i--)//i从最大层开始打印,一直打印到第1行,把整个上半部分打印完成
	{
		j = n - i;//计算本行空格数(每行都不一样,所以每轮循环都要计算一遍)
		while (j--)	printf(" ");//每小一层,符号序列前面要多一个空格
		k = 2 * i - 1;//当前行要输出的符号数
		while (k--) printf("%c",c);
		printf("\n");
	}
	for (i = 2; i <= n; i++)//i从2层开始打印
	{
		j = n - i;
		while (j--)	printf(" ");//每小一层,符号序列前面要多一个空格
		k = 2 * i - 1;
		while (k--) printf("%c", c);
		printf("\n");
	}
	printf("%d",sum);
	return 0;
}
  • 46
    点赞
  • 164
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值