C语言回型取数、螺旋矩阵

题目描述:

回形取数就是沿矩阵的边取数,若当前方向上无数可取或已经取过,则左转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

算法逆时针螺旋取数

                                

(1)先考虑m、n相等的情况  

        经观察可知,取数取n/2个轮回就可以了,每个轮回四次循环分别取向下、右、上、左的列或行。以第一个轮回为例,第一个轮回先向下取4个取到底,然后向右取3个去到底,再向上取3个到底,最后注意向左取两个不到底,到底会多取一次。做完后i++,进入下一次循环。

        代码a:把m、n视为相等即可

#include<stdio.h>
void printNumber(int a[][201],int m,int n);
int main(){
	int m,n;
	int a[201][201];
	scanf("%d%d",&m,&n);
	for(int i=0;i<m;i++){
		for(int j=0;j<n;j++){
			scanf("%d",&a[i][j]);
		}
	}
	printNumber(a,m,n);
	return 0;
}
void printNumber(int a[][201],int m,int n){
	int i,j,K;
    K=n<m?n:m;    //这里的k暂时当作n处理,m==n
	for(i=0;i<=n/2;i++){ //这里是小于等于当n=3时我们要做两次的
		for(j=i;j<=m-1-i;j++){
			printf("%d ",a[j][i]);
		}
		for(j=i+1;j<=n-1-i;j++){
			printf("%d ",a[m-i-1][j]);
		}
		for(j=m-1-i-1;j>=i;j--){
			printf("%d ",a[j][n-1-i]);
		}
		for(j=n-1-i-1;j>=i+1;j--){
			printf("%d ",a[i][j]);
		}
	}
}

  样例: 

(2)m、n不相等的时候   

我们看到末尾多取了一个4出来 

 这是为什么呢?

                

原因是,我们做了两次轮回4被取了两次。

首先我们知道当输入m,n不同时,我们取小的,做小的轮回就够了,比如100行2列,显然我们只需要做1次轮回。

        以 3 2为例,如上图,显然我们只需要做一次轮回,但输入3 3呢?我们就需要取两次。这不矛盾了吗?这可咋办呢?

        其实我们控制轮回的次数就能达到要求,于是我们令轮回的次数i=0 ; i<(1+k)/2,输入 3 2,   k 取小的等于2, (1+k)/2=1,做一次轮回,输入3 3时k=3,这时恰好做了两次轮回。

代码b

void printNumber(int a[][201],int m,int n){
	int i,j,k;
	k=m<n?m:n;
	for(i=0;i<(k+1)/2;i++){  //关键代码
		for(j=i;j<=m-1-i;j++){
			printf("%d ",a[j][i]);
		}
		for(j=i+1;j<=n-1-i;j++){
			printf("%d ",a[m-i-1][j]);
		}
		for(j=m-1-i-1;j>=i;j--){
			printf("%d ",a[j][n-1-i]);
		}
		for(j=n-1-i-1;j>=i+1;j--){
			printf("%d ",a[i][j]);
		}
	}
}

 

我们得到了正确的结果。

但是。。。你以为这就结束了吗?


当我们输入4 3时,看看会发生什么

 

仔细看,数一数,哎嘿,8后面咋多了个5,这是为撒呢?

我们输入 3 5,再看看

 我靠*#@&**,这咋又多了个8

我们以 4 3为例,3 5同理

其实,当我们做第二轮的时候5->8是向下的那一次,然后后面的向右需要从8后面的一个数开始,而我们第二次轮回只看5 8两个数,8后面没数,所以循环不执行,但是向上是可以的,我们向上是从8开始向上取一个数一直到最顶,其实就是取到了5,这就是最后的那个多余的小5子,然后向左取,同样不满足条件。那么现在我们既要保证取到5 和 8,但又不想要多余的5,我们就让向下和向右的去取,向上的时候我们加一个限制,即当次轮回的列数大于1,也就是i<n-1-i(n-1-i是这一轮第几列),同理,向左的时候我们令i<m-1-i。

代码c

void printNumber(int a[][201],int m,int n){
	int i,j,k;
	k=m<n?m:n;
	for(i=0;i<(k+1)/2;i++){
		for(j=i;j<=m-1-i;j++){
			printf("%d ",a[j][i]);
		}
		for(j=i+1;j<=n-1-i;j++){
			printf("%d ",a[m-i-1][j]);
		}
		for(j=m-1-i-1;j>=i;j--){
			if(i<n-1-i)printf("%d ",a[j][n-1-i]); //关键代码
		}
		for(j=n-1-i-1;j>=i+1;j--){
			if(i<m-1-i)	printf("%d ",a[i][j]);    //关键代码
		}
	}
}

 

 

当当当当,完成了!

ps:做题记录,先草草保存一下

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值