蓝桥杯练习——回形取数
题目描述
回形取数就是沿矩阵的边取数,若当前方向上无数可取或已经取过,则左转90度。一开始位于矩阵左上角,方向向下。
输入
输入第一行是两个不超过200的正整数m, n,表示矩阵的行和列。接下来m行每行n个整数,表示这个矩阵。
输出
输出只有一行,共mn个数,为输入矩阵回形取数得到的结果。数之间用一个空格分隔,行末不要有多余的空格。
样例输入
3 3 1 2 3 4 5 6 7 8 9
样例输出
1 4 7 8 9 6 3 2 5
这道题其实就是一个找规律的题,找好规律后几个循环就可以完成输出。
如上图所示,m为行数,n为列数,以一个m=5,n=5的5*5的矩阵为例,先忽略数字,把每一个数字当作矩阵中的一个点,由题意可知输出顺序是从外圈到内圈的逆时针顺序。以最外圈为例,其输出为从(0,0)到(m-1,0)的红色点,然后是橙色点,然后是黄色,最后是绿色,按照逆时针的顺序,外圈输出完毕。
如上图所示为第二圈,就是以(1,1)为起始点的圈,其顺序依旧是红、橙、黄、绿,第二圈输出完毕,最后是内圈(2,2),只有一个点,直接输出。这样,一个矩阵就输出完毕。
不难发现其中的输出规律,每次输出按圈逆时针输出,从外圈到内圈,起始点为(0,0),(1,1,),(2,2)。也就是说,每次只要找到起始点,然后按照顺序进行红、橙、黄、绿四次输出就可以了。
假设每次的起始点为(x,x)
红色的点为:(x,x)到(m-1-x,x) x坐标依次加1
橙色的点为:(m-1-x,x+1)到(m-1-x,n-1-x) y坐标依次加1
黄色的点为:(m-2-x,n-1-x)到(x,n-1-x) x坐标依次减1
绿色的点为:(x,n-2-x)到(m-1-x,x+1) y坐标依次减1
通过以上的规律,每次更换不同的起始点,通过四个for循环依次输出红、橙、黄、绿点,直至全部输完。
起始点就是每一圈的第一个点,想要找到起始点首选要知道圈数。
全是应该是(min(m,n)+1)/2 ,即行、列中最小数加一除2,除数是取整,由此可得圈数l,起始点则是(0,0)到(l-1,l-1)
第一个循环是起始点循环,然后每个起始点控制的输出再通过四个方向循环输出。
有两种特殊情况需要注意
1、m<n,且m为单数
这种情况在输出完外圈后,内圈只有一个从左到右的横向输出。
2、n<m,n为单数
这种情况在输出完外圈后,内圈只有一个从上到下的纵向输出
因此在四个方向输出前要判断是否是最内圈,且最内圈是否满足以上两种情况,如果满足则直接横向或者纵向输出,如果不满足再进行四个方向的输出。
代码:
#include<stdio.h>
int main()
{
int m,n;
scanf("%d%d",&m,&n); //输入行数和列数
int a[m][n];
int min=m<n?m:n;
int len=(min+1)/2;
for(int i=0;i<m;i++) //输入矩阵中的数字
{
for(int j=0;j<n;j++)
{
scanf("%d",&a[i][j]);
}
}
for(int x=0;x<len;x++) //按照起始点依次按圈逆时针输出
{
if(x==len-1&&((min+1)%2)==0) //如果是最内圈
{
if(m<n) //这种情况是横向输出
{
for(int i=x;i<n-x;i++)
{
printf("%d ",a[x][i]);
}
}
else //纵向输出
{
for(int i=x;i<m-x;i++)
{
printf("%d ",a[i][x]);
}
}
}
else
{
for(int i=x;i<m-x;i++) //红色的点
{
printf("%d ",a[i][x]);
}
for(int i=x+1;i<n-x;i++) //橙色的点
{
printf("%d ",a[m-1-x][i]);
}
for(int i=m-2-x;i>=x;i--) //黄色的点
{
printf("%d ",a[i][n-1-x]);
}
for(int i=n-2-x;i>x;i--) //绿色的点
{
printf("%d ",a[x][i]);
}
}
}
return 0;
}