题目:
描述
A fancy square image encryption algorithm works as follow:
0. consider the image as an N x N matrix
1. choose an integer k∈ {0, 1, 2, 3}
2. rotate the square image k * 90 degree clockwise
3. if N is odd stop the encryption process
4. if N is even split the image into four equal sub-squares whose length is N / 2 and encrypt them recursively starting from step 0
Apparently different choices of the k serie result in different encrypted images. Given two images A and B, your task is to find out whether it is POSSIBLE that B is encrypted from A. B is possibly encrypted from A if there is a choice of k serie that encrypt A into B.
输入
Input may contains multiple testcases.
The first line of the input contains an integer T(1 <= T <= 10) which is the number of testcases.
The first line of each testcase is an integer N, the length of the side of the images A and B.
The following N lines each contain N integers, indicating the image A.
The next following N lines each contain N integers, indicating the image B.
For 20% of the data, 1 <= n <= 15
For 100% of the data, 1 <= n <= 100, 0 <= Aij, Bij <= 100000000
输出
For each testcase output Yes or No according to whether it is possible that B is encrypted from A.
3 2 1 2 3 4 3 1 4 2 2 1 2 4 3 3 1 4 2 4 4 1 2 3 1 2 3 4 2 3 4 1 3 4 1 2 3 4 4 1 2 3 1 2 1 4 4 3 2 1 3 2
Yes No Yes
思路:
题解:hihocoder
自我理解:
利用等价类的思想,由于等价关系具备传递性,所以去判断A和B 是否可以通过变换转换为相同的样子。
而这个相同的样子,叫做最小表示,就是将等价类里的元素进行排序,其中最小的那个就是最小表示。
那么问题来了,怎么求最小表示了?
在本题中如果将矩阵分割为一些小矩阵,从左到右,从上到下,将这些小矩阵转化为最小表示,那么整体不就是最小表示了,所以采用了递归的思想。
#include<iostream>
#include<cstring>
using namespace std;
#define MAX 107
struct M{
int a[MAX][MAX],n;
M(int n=0):n(n){
// a=new int*[n];
// for(int i=0;i<n;++i)
// a[i]=new int[n];
}
// ~M(){
// for(int i=0;i<n;++i)
// delete[] a[i];
// delete[] a;
// }
};
//比较 A<B?1:0 ;
bool cmp(M& A,M& B,int s1,int e1,int s2,int e2){
for(int i=s1;i<e1;++i)
for(int j=s2;j<e2;++j)
if(A.a[i][j]<B.a[i][j])return true;
else if(A.a[i][j]>B.a[i][j])return false;
return false;
}
//对指定部分旋转90度
void rotate(M& m,int s1,int e1,int s2,int e2){
M t(m.n);
for(int i=0;i<e1-s1;++i)
for(int j=0;j<e2-s2;++j)
t.a[s1+i][s2+j]=m.a[e1-1-j][s2+i];
for(int i=s1;i<e1;++i)
for(int j=s2;j<e2;++j)
m.a[i][j]=t.a[i][j];
}
//对指定部分分为4块,将这4块旋转90度
void rotate_M(M& a,int s1,int e1,int s2,int e2){
M t(a.n);
int m=(e1-s1)/2;
for(int i=s1;i<e1;++i)
for(int j=s2;j<e2;++j)
t.a[i][j]=a.a[i][j];
//left_top
for(int i=s1;i<e1-m;++i)
for(int j=s2;j<e2-m;++j)
t.a[i][j]=a.a[i+m][j];
//right_top
for(int i=s1;i<e1-m;++i)
for(int j=s2+m;j<e2;++j)
t.a[i][j]=a.a[i][j-m];
//left_botton
for(int i=s1+m;i<e1;++i)
for(int j=s2;j<e2-m;++j)
t.a[i][j]=a.a[i][j+m];
//right_botton
for(int i=s1+m;i<e1;++i)
for(int j=s2+m;j<e2;++j)
t.a[i][j]=a.a[i-m][j];
for(int i=s1;i<e1;++i)
for(int j=s2;j<e2;++j)
a.a[i][j]=t.a[i][j];
}
void dfs(M& a,int s1,int e1,int s2,int e2){
M A(a.n);
if((e1-s1)&1){
A=a;
for(int k=1;k<4;++k){
rotate(A,s1,e1,s2,e2);
if(cmp(A,a,s1,e1,s2,e2)){
a=A;
}
}
}else{
//left_top
dfs(a,s1,(s1+e1)/2,s2,(s2+e2)/2);
//right_top
dfs(a,s1,(s1+e1)/2,(s2+e2)/2,e2);
//left_botton
dfs(a,(s1+e1)/2,e1,s2,(s2+e2)/2);
//right_botton
dfs(a,(s1+e1)/2,e1,(s2+e2)/2,e2);
A=a;
for(int k=1;k<4;++k){
rotate_M(A,s1,e1,s2,e2);
if(cmp(A,a,s1,e1,s2,e2)){
for(int i=s1;i<e1;++i)
for(int j=s2;j<e2;++j)
a=A;
}
}
}
}
int main(){
int T;
cin>>T;
while(T--){
int n;
cin>>n;
M a(n),b(n);
for(int i=0;i<n;++i)
for(int j=0;j<n;++j)
cin>>a.a[i][j];
for(int i=0;i<n;++i)
for(int j=0;j<n;++j)
cin>>b.a[i][j];
dfs(a,0,n,0,n);
dfs(b,0,n,0,n);
bool flag=true;
for(int i=0;i<n&&flag;++i)
for(int j=0;j<n;++j)
if(a.a[i][j]!=b.a[i][j]){
flag=false;
break;
}
if(flag)cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}