oj题目之有关旋转矩阵

一.有关题目

1.题目描述

Give you a n∗n matrix, if you rotate it 90 degrees(clockwise), we call it 1-Matrix, if you rotate it 180 degrees, we call it 2-Matrix, etc … This is said if you rotate the Matrix 90∗k degrees, then we call it k-Matrix. Now, your task is to calculate all the sum of i-Matrix (0<= i<= k).

(给定一个n*n阶的矩阵,如果你把它旋转90度(顺时针),我们就称之为1矩阵,如果你旋转180度,我们就称之为2矩阵,以此类推...这就是说如果你旋转90*k度,我们就称之为k矩阵。现在你的任务是计算所有i矩阵的和。)

2.输入描述

 There multiple test cases. Each test case begins with one integer n(1 <= n <= 10), following n lines, each line contains n integers, describe the original matrix, then a single line contains a k (1 <= k <= 10^8)described above. Process to end of file.

(有多个测试样例。每个样例以一个整数n(1<=n<=10),在这n行下面,每行包括n个整数,描述初始的矩阵,然后有单独一行包括k,描述上面的k,处理到文件末尾)

3.输出描述

For each case, output the sum of all the i-Matrix (0<= i<= k) in n lines. Each line there are n integers separated by one space. Note that there is no extra space at the end of each line.
(对于每个样例,在n行中输出所有n矩阵的和。每行有n个整数后面跟着一个空格。注意在每一行的最后不要有多余的空格)

4.样例输入
3

1 2 3

2 3 4

3 4 5

10

5.样例输出
33 32 31

34 33 32

35 34 33

二.题目解析

根据题目我们可以得到这是先把矩阵进行旋转然后对各个位置上的数字进行求和,比如在样例中,第一行第一列是1,旋转一次后第一行第一列是3,以此类推,11次(因为初始矩阵本身算一次所以是11次)分别是1,3,5,3,1,3,5,3,1,3,5加起来刚好是33所以输出的第一行第一列是33.

三.解题

根据前面的分析我们可以设定一个进行矩阵旋转的函数,每旋转一次就将旋转后的矩阵加在最后得到的那个矩阵上,而对于单纯的矩阵旋转,我们可以由三阶矩阵进行推广。对于一个三阶矩阵,旋转一次我们观察坐标的变化(1,1)变成(1,3),(1,2)变成(2,3),(1,3)变成(3,2)。。。以此类推我们可以得到变化前的纵坐标和变化后的横坐标是相等的,而变化前的横坐标加变化后的纵坐标加起来就是3也就是n,所以根据这样的规律我们可以编写出这个矩阵旋转的函数

void rotation(long long int a[][],int d)
{
	int p,q;
	long long int b[N][N]={0};
	for(p=0;p<d;p++)
	   for(q=0;q<d;q++)
	   {
	   	b[p][q]=a[d-1-q][p];
	   }
	   	for(p=0;p<d;p++)
	   for(q=0;q<d;q++)
	   {
	   	a[p][q]=b[p][q];
	   }
}

(其中的N为10,即n的最大值)

(这里要注意我们刚才分析的时候是变化前坐标在前面而变化后的坐标在后面,而在实际编写代码的时候,要输出的在前面,所以我们应该进行一个反向的处理)

有了这样的矩阵旋转函数我们就可以根据k的值进行旋转并加和了

这里提供两种办法

1.直接根据k的值进行循环相加

for(m=0;m<=k;m++)
    for(i=0;i<n;i++)
		{
			for(j=0;j<n;j++)
			y[i][j]+=x[i][j];
		}
	     	rotation(x,n);

(这样编写代码的时候在输出的时候是没有问题的,但是在我自己提交oj题目是,却出现了时间超出限制的问题,可能是由于k的值不确定可能引发数值过大的问题(自己也是小白也不是很理解))

2.第二种方法则是根据一种大循环套着小循环的思想来进行的,我们知道矩阵有四个角,所以每四次旋转就代表着一个大循环,所以我们可以根据这一点来编写代码

for(m=1;m<=4;m++)
 {
   rotation(x,n);
    for(i=0;i<n;i++)
	  for(j=0;j<n;j++)
		 y[i][j]+=x[i][j];
  }
  for(i=0;i<n;i++)
	for(j=0;j<n;j++)
	   y[i][j]=(k/4)*y[i][j];
for(m=1;m<=(k%4);m++)
    {
	 rotation(x,n);
      for(i=0;i<n;i++)
	 	 for(j=0;j<n;j++)
		     y[i][j]+=x[i][j];
       }

首先先把一个循环的加和算出来,然后再根据有几个这样的四组(即k/4)来乘前面所得到的结果,最后把除去四的倍数的次数循环(即k%4)加上就得到了最终的结果.

最后把结果输出出来

	for(i=0;i<n;i++)
		{
			for(j=0;j<n;j++)
			{
				printf("%lld ",y[i][j]+z[i][j]);
			}
			printf("\n");
		}
	}

注意最后的结果要加上第一次尚未进行旋转的矩阵,因为题目描述中说到0就是对矩阵不做旋转,这个也要加上。

最后加上其他的一些东西就组成了最终的代码

#include<stdio.h>
#define N 10
void rotation(long long int a[][10],int d);
int main()
{
	int n;
	while((scanf("%d",&n))!=EOF)
	{
		int k;
		long long int x[N][N]={0};
		long long int y[N][N]={0};
		long long int z[N][N]={0}; //这里要对x和n初始化不然会输出奇怪的数字 
		int i=0,j=0;
		int m=0;
		for(i=0;i<n;i++)
		{
			for(j=0;j<n;j++)
			{
				scanf("%lld",&x[i][j]);
			}
		}
		for(i=0;i<n;i++)
		{
			for(j=0;j<n;j++)
			{
				z[i][j]=x[i][j];
			}
		}
		scanf("%d",&k);
        for(m=1;m<=4;m++)
        {
        	rotation(x,n);
        	for(i=0;i<n;i++)
			   for(j=0;j<n;j++)
			      y[i][j]+=x[i][j];
        }
        for(i=0;i<n;i++)
	        for(j=0;j<n;j++)
		       y[i][j]=(k/4)*y[i][j];
		       for(m=1;m<=(k%4);m++)
       {
	        rotation(x,n);
         	for(i=0;i<n;i++)
	 	         for(j=0;j<n;j++)
		      	    y[i][j]+=x[i][j];
       }
			for(i=0;i<n;i++)
		{
			for(j=0;j<n;j++)
			{
				printf("%lld ",y[i][j]+z[i][j]);
			}
			printf("\n");
		}
	}
	return 0;
}
void rotation(long long int a[][10],int d)
{
	int p,q;
	long long int b[N][N]={0};
	for(p=0;p<d;p++)
	   for(q=0;q<d;q++)
	   {
	   	b[p][q]=a[d-1-q][p];
	   }
	   	for(p=0;p<d;p++)
	   for(q=0;q<d;q++)
	   {
	   	a[p][q]=b[p][q];
	   }
}

新人分享,希望大家多提建议,大家共同学习,一起进步。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值