打印沙漏
本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印
*****
***
*
***
*****
沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。
给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。
输入格式:
输入在一行给出1个正整数N(≤1000)和一个符号,中间以空格分隔。
输出格式:
首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。
输入样例:
19 *
输出样例:
*****
***
*
***
*****
2
Talk is cheap. Show me the code.
#include<iostream>
using namespace std;
int main()
{ int n=0;char sign='*';
cin>>n>>sign;
if(n==0)
{
cout<<n<<endl;
return 0;
}
int hourglass=1,increment=6;
int hourglass_arr[1000];
int remain=0,row=0;
for(int k=0;k<1000;k++,increment+=4)
{
hourglass_arr[k]=hourglass;
hourglass=hourglass+increment;
if(n<hourglass_arr[k])
{
remain=n-hourglass_arr[k-1];
row=k-1;
break;
}
}
int odd=1;
for(int k=0;k<row;k++)
{
odd=odd+2;
}
int blank=0;bool flag=false;
for(int temp_num=odd;temp_num>0;temp_num--)
{
if(!flag)
{
for(int k=blank;k>0;k--)
{
cout<<" ";
}
for(int k=odd-(2*blank);k>0;k--)
{
cout<<sign;
}
cout<<endl;
if(temp_num-1==odd/2)
{
flag=true;
odd=3;
blank--;
}
else
{
blank++;
}
}
else
{
for(int k=blank;k>0;k--)
{
cout<<" ";
}
for(int k=odd;k>0;k--)
{
cout<<sign;
}
cout<<endl;
blank--;
odd=odd+2;
}
}
cout<<remain;
}
解题思路
1000以内能够完美打印沙漏而无剩余的只有1 7 17 31 49 71 97 127 161 199 241 287 337 391 449 511 577 647 721 799 881 967这几个数,所以只需判断输入的N在哪个数之后即可,例如:输入N=19,则选中的数为17,剩余=19-17=2个。通过规律可以得到沙漏使用符号最多的一行也刚好为行数,例如:17时打印为5 3 1 3 5,共5行,所用符号最多的一行(最上面或最下面)也为5个。并且规律可以得到能够完美打印沙漏而无剩余的这几个数中行数刚好时按照1 3 5 7 9 …递增的,所以能够只需通过数组下标与值将行数(使用输入符号最多的一行)与选中的数联系起来,例如:输入N=19,选中的数为17为值,行数(使用输入符号最多的一行)5为下标。
分步代码解读
1.
int hourglass=1,increment=6;
int hourglass_arr[1000];
int remain=0,row=0;
for(int k=0;k<1000;k++,increment+=4)
{
hourglass_arr[k]=hourglass;
hourglass=hourglass+increment;
if(n<hourglass_arr[k])
{
remain=n-hourglass_arr[k-1];
row=k-1;
break;
}
}
hourglass_arr[1000]数组内存的是能够完美打印沙漏而无剩余的数(1000个显然大的多,可以适当减小)。这些数的计算方法(即规律)为1 + 6 = 7,7 + 10 = 17 ,17 + 14 =31 ,所以 hourglass_arr[0]=1,后续则为 hourglass_arr[1] = hourglass_arr[0] + 6,hourglass_arr[2] = hourglass_arr[1] + 10…,而 6 + 4 = 10,10 + 4 = 14(即 increment += 4)。
2.
int odd=1;
for(int k=0;k<row;k++)
{
odd=odd+2;
}
这部分代码就是根据能够完美打印沙漏而无剩余的这几个数中行数刚好时按照1 3 5 7 9 …递增的这一规律计算行数,得到行数就可以打印沙漏了,注意:行数也是所用*最多的一行(最上面或最下面)。
3.
int blank=0;bool flag=false;
for(int temp_num=odd;temp_num>0;temp_num--)
{
if(!flag)
{
for(int k=blank;k>0;k--)
{
cout<<" ";
}
for(int k=odd-(2*blank);k>0;k--)
{
cout<<sign;
}
cout<<endl;
if(temp_num-1==odd/2)
{
flag=true;
odd=3;
blank--;
}
else
{
blank++;
}
}
else
{
for(int k=blank;k>0;k--)
{
cout<<" ";
}
for(int k=odd;k>0;k--)
{
cout<<sign;
}
cout<<endl;
blank--;
odd=odd+2;
}
}
cout<<remain;
}
这部分代码就开始打印沙漏了。打印时先打印上半部分,符号前的空格从0递增一直到符号只需打印一个时,这是打印了行数的一半(注意:此时空格数要减一,因为中间对称轴我是算做下半部分。),然后我们符号就要从3开始奇数递增打印,并且空格数递减即可。最后别忘了输出剩余符号的个数。
4.
if(n==0)
{
cout<<n<<endl;
return 0;
}
注意输入N=0时,这种情况也要考虑,此时不打印直接输出剩余0即可。