hihocoder 1240 Image Encryption 矩阵的最小表示法


题意:给两个n*n(1 <= n <= 100)的矩阵,问a矩阵是否可以通过题目所给的方式变化为b矩阵。
题目所给的变化方式是指:
  1. 先把矩阵旋转,角度为0度,90度,180度,270度中的一个
  2. 如果矩阵边长为奇数,结束变换过程,否则,设边长为n,把矩阵分成4个(n/2*n/2)的矩阵,分别对它们进行1操作

思路:hihocoder官方的题解: http://hihocoder.com/discuss/question/3663
但是这个题解直接讲思路,并忽略了一个很关键的细节
所以自己重新讲下思路:
(自己想先讲一段离题废话,不想看的话直接看下一段)这是微软面试题,作为一道面试题,能够做出来当然是很好,但是万一做不出来呢,或者你需要想很久才能写出来呢?面试的时候我建议(从来没有参加过面试的学生开始厚颜无耻地给建议了)先讲自己的思路,当然思路不可能立刻想到,所以面试者可以一开始先说一个暴力算法,如果暴力算法都想不到,就自行改动题目,说如果这题换一个条件的话你会怎么做,然后接着说但是题目里没有你想要的条件,所以此法不通吧啦吧啦…………这样说的好处一是自己再开导自己的思路,二是以这个题目为中心,向面试官展示自己的知识面,三,运气好的话,也许面试官看你想得差不多了,会顺水推舟地给你一些提示,如果你表现得不错,就算没有解出这道题,面试官也会对你有很好的印象
回到正题:这类某物体不断变化的题目,我们一定会想到用某种特征码表示出题目中的物体,然后通过比对特征码的方法,来比较两个物体是否相同。
不妨想想一个首尾相接的循环串,通常我们用最小表示法来表示一个首尾相接的循环串
所以:题目里的矩阵是否有某种最小表示?
当然有的,所以解法很容易想到,把两个矩阵表示为最小表示,于是就ok了。
详细的思路可以见官方题解……
有一个小细节:当你把一个子矩阵表示为最小表示后,就要旋转子矩阵所在的大矩阵了,这时 不能改变子矩阵的形状,只能改变子矩阵的位置,换句话说,大矩阵的旋转,不可以对其子矩阵造成影响,不然原来是最小表示的子矩阵会因为再一次旋转,变为不是最小表示的

详见代码中的rotate()函数
#include<cstdio>
const int MAXN=101;
int a[MAXN][MAXN],b[MAXN][MAXN],c[MAXN][MAXN],d[MAXN][MAXN];
int cmp(int n,int a[MAXN][MAXN]=a,int b[MAXN][MAXN]=b,int x=0,int y=0){
	for(int i=0;i<n;++i) for(int j=0;j<n;++j)
		if(a[x+i][y+j]>b[x+i][y+j]) return 1;
		else if(a[x+i][y+j]<b[x+i][y+j]) return -1;
	return 0;
}
void memset(int a[MAXN][MAXN],int b[MAXN][MAXN],int x,int y,int n){
	for(int i=0;i<n;++i) for(int j=0;j<n;++j)
		a[x+i][y+j]=b[x+i][y+j];
}
void rorate(int a[MAXN][MAXN],int x,int y,int n,int ang=1){
	for(int t=1;t<=ang;++t){
		if(n&1){
			for(int i=0;i<n;++i) for(int j=0;j<n;++j)
				d[x+j][y+n-1-i]=a[x+i][y+j];
			memset(a,d,x,y,n);
		}
		else{
			n/=2;
			for(int i=0;i<n;++i) for(int j=0;j<n;++j){
				d[x+i][y+j+n]=a[x+i][y+j];
				d[x+i+n][y+j+n]=a[x+i][y+j+n];
				d[x+i][y+j]=a[x+i+n][y+j];
				d[x+i+n][y+j]=a[x+i+n][y+j+n];
			}
			memset(a,d,x,y,n*2);
		}
	}
}

void dfs(int a[MAXN][MAXN],int x,int y,int n){
	if(n<=1) return ;
	if(n&1){
		memset(c,a,x,y,n);
		for(int i=1;i<=3;++i){
			rorate(a,x,y,n);
			if(cmp(n,c,a,x,y)>0) memset(c,a,x,y,n);
		}
		memset(a,c,x,y,n);
		return ;
	}
	dfs(a,x,y,n/2);
	dfs(a,x+n/2,y,n/2);
	dfs(a,x,y+n/2,n/2);
	dfs(a,x+n/2,y+n/2,n/2);
	memset(c,a,x,y,n);
	for(int i=1;i<=3;++i){
		rorate(a,x,y,n);
		if(cmp(n,c,a,x,y)>0) memset(c,a,x,y,n);
	}
	memset(a,c,x,y,n);
}

int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int n;
		scanf("%d",&n);
		for(int i=0;i<n;++i) for(int j=0;j<n;++j)
			scanf("%d",&a[i][j]);
		for(int i=0;i<n;++i) for(int j=0;j<n;++j)
			scanf("%d",&b[i][j]);
		dfs(a,0,0,n);
		dfs(b,0,0,n);
//		putchar(10);
		if(!cmp(n,a,b,0,0)) puts("Yes");
		else puts("No");
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值