浅析洛谷P4924(一道普及/提高-的题目)的解决方法

题目描述:
Scarlet最近学会了一个数组魔法,她会在n×n二维数组上将一个奇数阶方阵按照顺时针或者逆时针旋转90°。首先,Scarlet会把1到n^2的正整数按照从左往右,从上至下的顺序填入初始的二维数组中,然后她会施放一些简易的魔法。
Scarlet既不会什么分块特技,也不会什么Splay套Splay,她现在提供给你她的魔法执行顺序,想让你来告诉她魔法按次执行完毕后的二维数组。
输入格式:
第一行两个整数n,m,表示方阵大小和魔法施放次数。接下来m行,每行44个整数x,y,r,z,表示在这次魔法中,Scarlet会把以第x行,第y列为中心的2r+1阶矩阵按照某种时针方向旋转,其中z=0表示顺时针,z=1表示逆时针。
输出格式:
输出n行,每行有n个用空格隔开的数,表示最终所得的矩阵
说明/提示:
对于50%的数据,满足r=1
对于100%的数据1≤n,m≤500,满足1 ≤ x – r ≤ x + r ≤ n, 1 ≤ y – r ≤ y + r ≤ n.
样例输入
5 4
2 2 1 0
3 3 1 1
4 4 1 0
3 3 2 1
输出
5 10 3 18 15
4 19 8 17 20
1 14 23 24 25
6 9 2 7 22
11 12 13 16 21
思路分析:
由于上学期我在学校的oj上做过一道图像旋转的题(操作就是把一个m×n的矩阵顺时针旋转90°),所以在刚看到这道题的时候,我想的是用之前的思路,把它定义成一个函数,然后逆时针旋转90°可以看做是使用三次那个函数(后来发现还有很多细节要处理)。根据每一次所给的r[i],可以确定出需要旋转的矩阵所在行和列的范围,也就是边界,对它用所定义的函数即可。
求解过程的说明:
代码是用C语言编写的。
第一次在定义函数的过程中出现了问题,主要是C语言中return不能直接返回一个数组,需要借助指针,通过返回对应类型指针的方式,返回数组。
于是第二次我就直接把这个过程写到主函数里面了,然后这个时候如果再用顺时针旋转270°的方式来表示逆时针旋转90°会有些繁琐,所以更改为直接寻找顺时针旋转90°和逆时针旋转90°的规律,分别进行。通过探究发现,对于n×n的矩阵中的任意一个元素a[i][j],顺时针旋转90°后,它的行和列相应的变为j,n-i-1(由于是从第0行,第0列开始,所以用n-1减i),逆时针旋转90°后,它的行和列相应的变为n-j-1,i。然后在本地测试了样例,发现还是存在一些问题。调试之后发现了两个问题:
第一,如果只用一个二维数组a的话,没有办法存储临时变量,这在输出中表示为1-25中的数字有的会出现多次;
第二,矩阵的一部分旋转和整体进行旋转是不完全一样的(一开始我以为是一样的),比如对5×5的矩阵(元素为题目要求那样输入)的左上角的3×3的矩阵进行逆时针旋转90°,那么1由在a[0][0]的位置变为在a[2][0]的位置上,但整体旋转却是转到a[4][0]的位置。
基于此,我进行了第三次的尝试:先是定义另一个二维数组b来存储a的每一次变换之后的元素,然后对于部分旋转矩阵的问题,可以看做是一个2r+1阶的矩阵通过平移后对应a的行与列,这样2r+1阶的矩阵就是一个对自己的整体旋转,符合上面找到的行与列的变换规律。然后本地过了之后一次就AC了。

#include
int main()
{
	int n,m,i,j,k,a[500][500]={0},b[500][500]={0},x[500],y[500],r[500],z[500],t=1;
	scanf("%d %d",&n,&m);
	for(i=0;i<m;i++)
	{
		scanf("%d %d %d %d",&x[i],&y[i],&r[i],&z[i]);	
	}
	for(i=0;i<n;i++)
	{
		for(j=0;j<n;j++)
		{
			a[i][j]=t;b[i][j]=t;
			t++;
		}
	}
	for(i=0;i<m;i++)
	{
		if(z[i]==1)
		{
			for(j=0;j<=2*r[i];j++)
			{
				for(k=0;k<=2*r[i];k++)
				{
					b[j+x[i]-r[i]-1][k+y[i]-r[i]-1]=a[k+x[i]-r[i]-1][y[i]+r[i]-j-1];
				}
			}
		}
		if(z[i]==0)
		{
			for(j=0;j<=2*r[i];j++)
			{
				for(k=0;k<=2*r[i];k++)
				{
					b[j+x[i]-r[i]-1][k+y[i]-r[i]-1]=a[x[i]+r[i]-k-1][y[i]-r[i]+j-1];
				}
			}
		}
		for(j=x[i]-r[i]-1;j<x[i]+r[i];j++)
		{
			for(k=y[i]-r[i]-1;k<y[i]+r[i];k++)
			{
				a[j][k]=b[j][k];
			}
		}	
	}
	for(i=0;i<n;i++)
	{
		for(j=0;j<n;j++)
		{
			printf("%d ",b[i][j]);
		}
		printf("\n");
	}
	return 0;
}

你可能感兴趣的:(洛谷杂记,c语言)