L1-002 打印沙漏 C语言/Python版(6行代码)
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
.....以此类推,用等差数列求和公式可得:
④
∵ ⑤
设h=g(n),则
=>
=>
=>
这个化简其实只需要高中数学良好就可以完成,计算熟练者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为例:
不难得出 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;
}
欢迎各位交流探讨,发表合理评论或提意见。
上一篇: 【常用函数】split()
下一篇: R语言开发之字符串操作基础了解下