7-1 剥洋葱(15 分)
布告,布告! 应老师要求,我们要做一道打印图形的题目,这是程序员最基本的能力。 那废话不多说,我们来说要求的图形 AAAAA ABBBA ABCBA ABBBA AAAAA 就是外到内,从A到Z。每一层都是一种字母,最里面的一层为一个,即最中心的一个。
输入格式:
一行,一个整数,即图形的层数
输出格式:
如上述图形
输入样例:
3
输出样例:
AAAAA
ABBBA
ABCBA
ABBBA
AAAAA
这个题开始想的时候真的很头痛,不知道怎么输出。其实这可以看成一个数组,可以发现这个数组是一个正方形的,最外面一层全是A,向里面一层全是B,依次下去。如果输入的是26的话,会有26层,从外向内是A——Z。
(首先注明,这张图以及下面那张四分之一的图是我在其他博客里找到的,所以说我是有借鉴大佬的博客的)
我们可以把打出来的字符矩阵看成数组的形式,如上图显示就是打印n=4时的字符矩阵,蓝色的是A,浅蓝色的是B,黄色的是C,红色的是D。可以发现,他是有规律的,从外向内一层一层的,就像剥洋葱一样。我们还可以发现,这个数组是对称的,上下对称,左右对称,所以我们只要确定出来1/4数组的内容就可以通过“折叠”来把数组整个确定下来。
如上图,这就是1/4数组,在可以可以发现,蓝色的(即A)数组坐标中较小的是0,浅蓝色的(即B)数组较小的是1,黄色的(即C)数组坐标中较小的是2,红的色(即D)数组坐标中较小的是3。由此可见,每一个字符对应了数组中不同的特征,所以可以用这个特征来确定数组每个位置对应的字符。然后向右对称,再然后让下对称。(这是数组的左上角,数组的右下角也有对应的特征,A中较大的都是6,B中较大的都是5,C中较大的都是4,D中是3。但是左下角的右上角则不一样。)
下面代码是从1开始的,因我我感觉从一开始更好想,我习惯从1开始。
#include<stdio.h> int min(int x,int y) \\这个函数是比较数组坐标那一个小的函数,返回两者之中的较小的 { if(x<y) return x; else return y; } int main() { int n,i,j; char **p; \\这是定义了一个二级指针,下面用二级指针动态申请二维数组。 char a[27]={'\0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}; \\首先定义一个字符数组,给其赋值,我这里是从1开始的。 scanf("%d",&n); p=(char **)malloc((2*n-1)*sizeof(char)); \\这是申请2*n-1行。 for(i=1;i<2*n;i++) \\这个for循环是对上面申请的每一个在申请2*n-1列,这样就是2*n-1行2*n-1列的数组 了。 p[i]=(char *)malloc((2*n-1)*sizeof(char)); for(i=1;i<=n;i++) \\这里是先确认二维数组1/4(右上角对应的字符) for(j=1;j<=n;j++) { int x=min(i,j); \\调用min函数,返回坐标中较小的 p[i][j]=a[x]; \\较小的为1就对应A(即a[1]),较小的为二即对应B(a[2]),这里就体现出上面数组a的作用了,有了数组a,就不用if判断是几对应谁了,以前我用了26个if判断26个对应的字母 } for(i=1;i<=n;i++) for(j=1;j<=n;j++) \\这里是将数组向右对称,行数是从1——n,列数是从1——n,一行一行进行对称。 { p[i][2*n-j]=p[i][j]; \\第一行第一列对称的第一行第2*n-1列,第一行第二列对应到第二行2*n-2列,所以行不变,列对称。 } for(i=1;i<=n;i++) \\这里是向右对称之后的向下对称。行数从1——n,列数从1——2*n-1(因为上面已经向右对称了) for(j=1;j<2*n;j++) p[2*n-i][j]=p[i][j]; \\第一行第j列对应第2*n-1行第j列,即第i行第j列对应第2*n-i行第j列(i<=n) 列不变,行变。 for(i=1;i<2*n;i++) { for(j=1;j<2*n;j++) printf("%c",p[i][j]); \\输出数组,就能呈现出洋葱的效果。 printf("\n"); } return 0; }