欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

L1-002 打印沙漏 C语言/Python版(6行代码)

程序员文章站 2022-07-16 15:36:45
...

L1-002 打印沙漏 (20 分)

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

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

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

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

输入格式:

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

输出格式:

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

输入样例:

19 *

输出样例:

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

 


解题思路:解法一

记输入值为: n  ch    (即样例中n=19,ch='*')此题可以分为两个部分进行:

①根据被打印符号总数n,求出沙漏上三角部分行数h,则总行数为 (2h-1) 。

②打印的上半行数为h的沙漏

③计算余下未被打印的符号remain

①n转h:解法一

先按余下符号数remain=0时的情况分析n和r。记f(r)为r行沙漏所需符号数:

则f(1)=1= 1*2 -1

f(2)=3+1+3= (1+3)*2-1

f(3)=5+3+1+3+5 = (1+3+5)*2-1

.....以此类推,用等差数列求和公式可得:

L1-002 打印沙漏 C语言/Python版(6行代码) 

L1-002 打印沙漏 C语言/Python版(6行代码)   

设h=g(n),则 L1-002 打印沙漏 C语言/Python版(6行代码)

=>   L1-002 打印沙漏 C语言/Python版(6行代码)

=>   L1-002 打印沙漏 C语言/Python版(6行代码)

=> L1-002 打印沙漏 C语言/Python版(6行代码)

这个化简其实只需要高中数学良好就可以完成,计算熟练者1分钟都不用。

对于数学功底较弱的同学,也可以根据式用迭代的方法(见解法二)根据n求出对应的h。只是程序执行的时间稍微长一点,代码稍微多一点。

②沙漏:解法一(函数法)

之所以不以沙漏的总行数r为输入,而要定义上半三角行数h,是有原因的。

要打印这个沙漏无非就是确定要打印的每一行的空格数s ,和ch字符数 c。

注意不能用Python自动居中对齐的打印方法,因为每一行最后一个字符必须是ch,不能用空格补齐。

定义每一行空格数和ch字符数关于h的数列函数分别为 S(h)和 C(h)

则 C(1)=[1],C(2)=[3,1,3],C(3)=[5,3,1,3,5],C(4)=[7,5,3,1,3,5,7]

     S(1)=[0],S(2)=[0,1,0],S(3)=[0,1,2,1,0],S(4)=[0,1,2,3,2,1,0]

首先S(h)的规律比较明显

本文定义:数与数列的运算或函数,是对数列中的每个元素都采取同样运算。

记 J(h+1) = h -S(h+1)  (提示:就是将S(h+1)中的每个元素都用h去减)

直接上图,以h=6为例:

L1-002 打印沙漏 C语言/Python版(6行代码)

不难得出  C(h)= 2J(h) +1

则 S(h+1) = h - J(h+1)

只要在遍历中整出 [5,4,3,2,1,0,1,2,3,4,5]的效果即可,那不就是[-5,-4,-3,-2,-1,0,1,2,3,4,5]取绝对值吗?

由此可以得到打印漏斗的函数,Python代码如下:

def sand_clock(ch,h):
    for n in range(1-h,h):  #如h=5时表示 [-4,-3,-2,-1,0,1,2,3,4]
        print(' '*(h-1-abs(n))+ch*(2*abs(n)+1))	#Python里 字符串*k,其中k为整数,表示该字符串重复k次

③剩余字符:

解法一:配合①中的函数解法,由 h=g(n)得到h,再由 f(h)=n0得到实际使用的符号数量n0,remain = n - n0。

解法二:笨方法,在打印沙漏的循环中累加统计已用字符数量,最后用n减去即可。

解法一代码:

Python版本:(就不写成函数了)

n,ch=input().split(' ')
n=int(n)	#ch的总数量
h=int(((n+1)/2)**0.5)		# h*2-1 为行数,也是首行的ch数量
for i in map(abs,range(1-h,h)):    #map(abs,list)表示对list的每个元素都取绝对值
    print(' '*(h-1 -i)+ch*(2*i+1))     # h-i 个空格,接(2*i+1)个ch
print( n - (2*h**2 -1) )	#ch实际数量为: 2 * h^2 -1

C语言版:

#include<stdio.h>
#include<math.h>
void print(char ch, int count) {
	while (count-- > 0)putchar(ch);
}	//print(ch,c):打印ch字符c遍。
int main() {
	int n, ch, h,i;
	scanf("%d %c", &n, &ch);
	h = (int)sqrt((n + 1) / 2); //h=g(n)
	for (i = 1-h; i < h; i++){
		int j = abs(i);
		print(' ', h - 1 - j);	//空格
		print(ch, 2 * j + 1);	//ch
		putchar('\n');	//换行
	}
	printf("%d", n - (2 * h*h - 1));
	return 0;
}

解法二:笨办法

由于本人是直接按解法一秒杀此题的,只是怕同学不理解,就写个解法二:

解法二就不解释这么多了,直接上代码,看注释:

#include <stdio.h>
void print(char ch, int count) {
	while (count-- > 0)putchar(ch);
}	//print(ch,c):打印ch字符c遍。
void printLine(char ch, int j, int width) {
	print(' ', j);	//j为空格数量
	print(ch, width - 2*j);	//width一行总宽度  - 两侧的空格数量2j
	putchar('\n');	//换行(右侧的空格不需要也不允许真正地输出)
}	//打印沙漏专用,ch为待打印字符,h为上三角层数
int main(){
	int n, n0 = 1;	//n ch即为题目输入。n0是沙漏实际打印字符个数
	char ch;	//样例中ch=='*'
	int h = 1;	//沙漏上三角层数
	scanf("%d %c", &n, &ch);
	while (1){	//迭代法试出
		int temp = n0 + 2 * (2 * h + 1);	//新增加首末两行的ch数量
		if (temp <= n) {		//没有超出n
			n0 = temp;	h++;
		}else break;	//否则超出则跳出
	}
	int j, row = 2 * h - 1;	//j为空格数量,row为总行数==首末行ch数量
	for (j = 0; j<h; j++) {		//打印上半部分(含中间)
		printLine(ch, j, row);
	}
	for (j = h-2; j >= 0; j--){	//打印下半部分(不含中间)
		printLine(ch, j, row);
	}
	printf("%d", n - n0);
	return 0;
}

欢迎各位交流探讨,发表合理评论或提意见。