#include<cstdio>
#include<algorithm>
#include<stack>
#include<queue>
#include<deque>
#include<vector>
#include<string>
#include<string.h>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<map>
#include<set>
#include<iostream>
#include<sstream>
#include<cctype>
#define fi first
#define se second
#define rep(i,n) for(int i = 0; i < n; ++i)
#define rrep(i,n) for(int i = 1; i <= n; ++i)
#define drep(i,n) for(int i = n-1; i >= 0; --i)
#define gep(i,g,j) for(int i = g.head[j]; i != -1; i = g.e[i].next)
#define each(it,c) for(__typeof((c).begin()) it=(c).begin();it!=(c).end();it++)
#define rng(a) a.begin(),a.end()
#define maxs(x,y) x = max(x,y)
#define mins(x,y) x = min(x,y)
#define pb push_back
#define sz(x) (int)(x).size()
#define pcnt __builtin_popcount
#define snuke srand((unsigned)clock()+(unsigned)time(NULL))
using namespace std;
typedef long long int ll;
typedef pair<int,int> P;
typedef vector<int> vi;

const int MX = 1000005, INF = 1000010000;
const ll LINF = 1000000000000000000ll;
const double eps = 1e-10;
const int dx[] = {-1,-1,-1,0,0,1,1,1}, dy[] = {-1,0,1,-1,1,-1,0,1}; //<^>v

int n, m;
int s[35][35];
int t[35][35];
int u[35][35];
int cnt[905];
int used[35][35], ui;
int px[35][35], py[35][35];
vector<P> p;

int x, y;
void bfs(int a, int b) {
	queue<P> q;
	q.push(P(a,b));
	used[a][b] = ++ui;
	px[a][b] = -1;
	while (q.size()) {
		int i = q.front().fi, j = q.front().se; q.pop();
		if (i == x && j == y) break;
		rep(v,8) {
			int ni = i+dx[v], nj = j+dy[v];
			if (ni<0||nj<0||ni>=n||nj>=m||s[ni][nj]==-1||used[ni][nj]==ui) continue;
			used[ni][nj] = ui;
			px[ni][nj] = i;
			py[ni][nj] = j;
			q.push(P(ni,nj));
		}
	}
	while (px[x][y] != -1) {
		int i = x, j = y;
		x = px[i][j]; y = py[i][j];
		swap(s[i][j],s[x][y]);
		p.pb(P(x,y));
	}
}
void f() {
	rep(i,n)rep(j,m) if (t[n-1][m-1] == s[i][j]) x = i, y = j;
	p.pb(P(x,y));
	rep(i,n-2) {
		rep(j,m) {
			int a, b;
			rep(ai,n)rep(bi,m) if (s[ai][bi] == t[i][j]) a = ai, b = bi;
			s[a][b] = -1;
			while (b > j) {
				bfs(a,b-1);
				swap(s[x][y],s[a][b]);
				swap(y,b);
				p.pb(P(x,y));
			}
			while (b < j) {
				bfs(a,b+1);
				swap(s[x][y],s[a][b]);
				swap(y,b);
				p.pb(P(x,y));
			}
			while (a > i) {
				bfs(a-1,b);
				swap(s[x][y],s[a][b]);
				swap(a,x);
				p.pb(P(x,y));
			}
		}
	}
	rep(j,m-1) {
		for(int i = n-2; i < n; ++i) {
			int a, b;
			rep(ai,n)rep(bi,m) if (s[ai][bi] == t[i][j]) a = ai, b = bi;
			s[a][b] = -1;
			while (a > i) {
				bfs(a-1,b);
				swap(s[x][y],s[a][b]);
				swap(x,a);
				p.pb(P(x,y));
			}
			while (a < i) {
				bfs(a+1,b);
				swap(s[x][y],s[a][b]);
				swap(x,a);
				p.pb(P(x,y));
			}
			while (b > j) {
				bfs(a,b-1);
				swap(s[x][y],s[a][b]);
				swap(b,y);
				p.pb(P(x,y));
			}
		}
	}
	if (x != n-1) p.pb(P(x+1,y));
	printf("%d\n",sz(p)-1);
	rep(i,sz(p)) {
		printf("%d %d\n",p[i].fi+1,p[i].se+1);
	}
}

void check() {
	rep(i,sz(p)-1) {
		swap(u[p[i].fi][p[i].se],u[p[i+1].fi][p[i+1].se]);
	}
	rep(i,n){rep(j,m) printf("%d ",u[i][j]); puts("");}
}

int main(){
	scanf("%d%d",&n,&m);
	rep(i,n)rep(j,m) scanf("%d",&s[i][j]);
	rep(i,n)rep(j,m) scanf("%d",&t[i][j]);
	rep(i,n)rep(j,m) cnt[s[i][j]]++;
	rep(i,n)rep(j,m) cnt[t[i][j]]--;
	rep(i,905) if (cnt[i]) {
		puts("-1");
		return 0;
	}
	if (n == 1) {
		rep(si,m){
			rep(i,n)rep(j,m) u[i][j] = s[i][j];
			for (int k = si+1; k < m; ++k) {
				swap(u[0][k],u[0][k-1]);
				bool ok = true;
				rep(i,n)rep(j,m) if(u[i][j] != t[i][j]) ok = false;
				if (ok) {
					printf("%d\n",k-si);
					for(int i = si; i <= k; ++i) {
						printf("%d %d\n",1,i+1);
					}
					return 0;
				}
			}
		}
		rep(si,m){
			rep(i,n)rep(j,m) u[i][j] = s[i][j];
			for (int k = si-1; k >= 0; --k) {
				swap(u[0][k],u[0][k+1]);
				bool ok = true;
				rep(i,n)rep(j,m) if(u[i][j] != t[i][j]) ok = false;
				if (ok) {
					printf("%d\n",si-k);
					for(int i = si; i >= k; --i) {
						printf("%d %d\n",1,i+1);
					}
					return 0;
				}
			}
		}
		puts("-1");
		return 0;
	}
	if (m == 1) {
		rep(si,n){
			rep(i,n)rep(j,m) u[i][j] = s[i][j];
			for (int k = si+1; k < n; ++k) {
				swap(u[k][0],u[k-1][0]);
				bool ok = true;
				rep(i,n)rep(j,m) if(u[i][j] != t[i][j]) ok = false;
				if (ok) {
					printf("%d\n",k-si);
					for(int i = si; i <= k; ++i) {
						printf("%d %d\n",i+1,1);
					}
					return 0;
				}
			}
		}
		rep(si,n){
			rep(i,n)rep(j,m) u[i][j] = s[i][j];
			for (int k = si-1; k >= 0; --k) {
				swap(u[k][0],u[k+1][0]);
				bool ok = true;
				rep(i,n)rep(j,m) if(u[i][j] != t[i][j]) ok = false;
				if (ok) {
					printf("%d\n",si-k);
					for(int i = si; i >= k; --i) {
						printf("%d %d\n",i+1,1);
					}
					return 0;
				}
			}
		}
		puts("-1");
		return 0;
	}

	rep(i,n)rep(j,m) u[i][j] = s[i][j];
	f();
	//check();

	return 0;
}


#include<cstdio>
#include<algorithm>
#include<stack>
#include<queue>
#include<deque>
#include<vector>
#include<string>
#include<string.h>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<map>
#include<set>
#include<iostream>
#include<sstream>
#include<cctype>
#define fi first
#define se second
#define rep(i,n) for(int i = 0; i < n; ++i)
#define rrep(i,n) for(int i = 1; i <= n; ++i)
#define drep(i,n) for(int i = n-1; i >= 0; --i)
#define gep(i,g,j) for(int i = g.head[j]; i != -1; i = g.e[i].next)
#define each(it,c) for(__typeof((c).begin()) it=(c).begin();it!=(c).end();it++)
#define rng(a) a.begin(),a.end()
#define maxs(x,y) x = max(x,y)
#define mins(x,y) x = min(x,y)
#define pb push_back
#define sz(x) (int)(x).size()
#define pcnt __builtin_popcount
#define snuke srand((unsigned)clock()+(unsigned)time(NULL))
using namespace std;
typedef long long int ll;
typedef pair<int,int> P;
typedef vector<int> vi;

const int MX = 1000005, INF = 1000010000;
const ll LINF = 1000000000000000000ll;
const double eps = 1e-10;
const int dx[] = {-1,-1,-1,0,0,1,1,1}, dy[] = {-1,0,1,-1,1,-1,0,1}; //<^>v

int n, m;
int s[35][35];
int t[35][35];
int u[35][35];
int cnt[905];
int used[35][35], ui;
int px[35][35], py[35][35];
vector<P> p;

int x, y;
void bfs(int a, int b) {
	queue<P> q;
	q.push(P(a,b));
	used[a][b] = ++ui;
	px[a][b] = -1;
	while (q.size()) {
		int i = q.front().fi, j = q.front().se; q.pop();
		rep(v,8) {
			int ni = i+dx[v], nj = j+dy[v];
			if (ni<0||nj<0||ni>=n||nj>=m||s[ni][nj]==-1||used[ni][nj]==ui) continue;
			used[ni][nj] = ui;
			px[ni][nj] = i;
			py[ni][nj] = j;
			q.push(P(ni,nj));
		}
	}
	while (px[x][y] != -1) {
		int i = x, j = y;
		x = px[i][j]; y = py[i][j];
		swap(s[i][j],s[x][y]);
		p.pb(P(x,y));
	}
}
void f() {
	rep(i,n)rep(j,m) if (t[n-1][m-1] == s[i][j]) x = i, y = j;
	p.pb(P(x,y));
	rep(i,n-2) {
		rep(j,m) {
			int a, b;
			rep(ai,n)rep(bi,m) if (s[ai][bi] == t[i][j]) a = ai, b = bi;
			s[a][b] = -1;
			while (b > j) {
				bfs(a,b-1);
				swap(s[x][y],s[a][b]);
				swap(y,b);
				p.pb(P(x,y));
			}
			while (b < j) {
				bfs(a,b+1);
				swap(s[x][y],s[a][b]);
				swap(y,b);
				p.pb(P(x,y));
			}
			while (a > i) {
				bfs(a-1,b);
				swap(s[x][y],s[a][b]);
				swap(a,x);
				p.pb(P(x,y));
			}
		}
	}
	rep(j,m-1) {
		for(int i = n-2; i < n; ++i) {
			int a, b;
			rep(ai,n)rep(bi,m) if (s[ai][bi] == t[i][j]) a = ai, b = bi;
			s[a][b] = -1;
			while (a > i) {
				bfs(a-1,b);
				swap(s[x][y],s[a][b]);
				swap(x,a);
				p.pb(P(x,y));
			}
			while (a < i) {
				bfs(a+1,b);
				swap(s[x][y],s[a][b]);
				swap(x,a);
				p.pb(P(x,y));
			}
			while (b > j) {
				bfs(a,b-1);
				swap(s[x][y],s[a][b]);
				swap(b,y);
				p.pb(P(x,y));
			}
		}
	}
	if (x != n-1) p.pb(P(x+1,y));
	printf("%d\n",sz(p)-1);
	rep(i,sz(p)) {
		printf("%d %d\n",p[i].fi+1,p[i].se+1);
	}
}

void check() {
	rep(i,sz(p)-1) {
		swap(u[p[i].fi][p[i].se],u[p[i+1].fi][p[i+1].se]);
	}
	rep(i,n){rep(j,m) printf("%d ",u[i][j]); puts("");}
}

int main(){
	scanf("%d%d",&n,&m);
	rep(i,n)rep(j,m) scanf("%d",&s[i][j]);
	rep(i,n)rep(j,m) scanf("%d",&t[i][j]);
	rep(i,n)rep(j,m) cnt[s[i][j]]++;
	rep(i,n)rep(j,m) cnt[t[i][j]]--;
	rep(i,905) if (cnt[i]) {
		puts("-1");
		return 0;
	}
	if (n == 1) {
		rep(si,m){
			rep(i,n)rep(j,m) u[i][j] = s[i][j];
			for (int k = si+1; k < m; ++k) {
				swap(u[0][k],u[0][k-1]);
				bool ok = true;
				rep(i,n)rep(j,m) if(u[i][j] != t[i][j]) ok = false;
				if (ok) {
					printf("%d\n",k-si);
					for(int i = si; i <= k; ++i) {
						printf("%d %d\n",1,i+1);
					}
					return 0;
				}
			}
		}
		rep(si,m){
			rep(i,n)rep(j,m) u[i][j] = s[i][j];
			for (int k = si-1; k >= 0; --k) {
				swap(u[0][k],u[0][k+1]);
				bool ok = true;
				rep(i,n)rep(j,m) if(u[i][j] != t[i][j]) ok = false;
				if (ok) {
					printf("%d\n",si-k);
					for(int i = si; i >= k; --i) {
						printf("%d %d\n",1,i+1);
					}
					return 0;
				}
			}
		}
		puts("-1");
		return 0;
	}
	if (m == 1) {
		rep(si,n){
			rep(i,n)rep(j,m) u[i][j] = s[i][j];
			for (int k = si+1; k < n; ++k) {
				swap(u[k][0],u[k-1][0]);
				bool ok = true;
				rep(i,n)rep(j,m) if(u[i][j] != t[i][j]) ok = false;
				if (ok) {
					printf("%d\n",k-si);
					for(int i = si; i <= k; ++i) {
						printf("%d %d\n",i+1,1);
					}
					return 0;
				}
			}
		}
		rep(si,n){
			rep(i,n)rep(j,m) u[i][j] = s[i][j];
			for (int k = si-1; k >= 0; --k) {
				swap(u[k][0],u[k+1][0]);
				bool ok = true;
				rep(i,n)rep(j,m) if(u[i][j] != t[i][j]) ok = false;
				if (ok) {
					printf("%d\n",si-k);
					for(int i = si; i >= k; --i) {
						printf("%d %d\n",i+1,1);
					}
					return 0;
				}
			}
		}
		puts("-1");
		return 0;
	}

	rep(i,n)rep(j,m) u[i][j] = s[i][j];
	f();
	//check();

	return 0;
}


#include <bits/stdc++.h>
#define REP(a,b) for(int a=0; a<(b); ++a)
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define FWDS(a,b,c,d) for(int a=(b); a<(c); a+=d)
#define BCK(a,b,c) for(int a=(b); a>(c); --a)
#define x first
#define y second
#define pb push_back
#define re real()
#define im imag()

using namespace std;

typedef pair<int, int> PII;

int n, m, a, b;
int tmp[33][33];
int source[33][33];
int target[33][33];
vector<PII> R;

void save(){
	FWD(i,0,n) FWD(j,0,m) tmp[i][j] = source[i][j];
}

void load(){
	R.clear();
	FWD(i,0,n) FWD(j,0,m) source[i][j] = tmp[i][j];
}

void check(){
	FWD(i,0,n) FWD(j,0,m) if(source[i][j] != target[i][j]) return;
	printf("%d\n", (int)R.size()-1);
	for(PII r : R) printf("%d %d\n", r.x+1, r.y+1);
	exit(0);
}

void make(int x, int y){
	swap(source[R.back().x][R.back().y], source[x][y]);
	R.push_back(PII(x,y));
	a = x; b = y;
}

int main(){
	scanf("%d %d", &n, &m);
	FWD(i,0,n) FWD(j,0,m) scanf("%d", &source[i][j]);
	FWD(i,0,n) FWD(j,0,m) scanf("%d", &target[i][j]);
	save();
	if(n == 1 || m == 1){
		//printf("degenerate\n");
		FWD(s,0,max(n,m)){
			for(int d=-1; d<=1; d+=2){
				//printf("%d %d\n", s, d);
				load();
				R.push_back(PII(n==1?0:s,n==1?s:0));
				for(int i=s+d;-1<i&&i<max(n,m);i+=d){
					make(n==1?0:i,n==1?i:0);
					check();
				}
			}
		}
		printf("-1\n");
		return 0;
	}
	FWD(i,0,n) FWD(j,0,m) if(source[i][j] == target[n-1][m-1]) a = i, b = j;
	R.push_back(PII(a,b));
	//printf("grab %d %d\n", a, b);
	FWD(i,0,n-2) FWD(j,0,m){
		//printf("setting %d %d\n", i, j);
		while(a > i) make(a-1, b);
		while(b > j) make(a, b-1);
		PII s = PII(i,j);
		FWD(p,0,n) FWD(q,0,n) if(PII(p,q) > s && source[p][q] == target[i][j])
			s = PII(p,q);
		if(s == PII(i,j)){
			printf("-1\n");
			return 0;
		}
		for(;;){
			while(a < s.x) make(a+1, b);
			if(b == s.y)
				--s.x;
			else
				--s.y;
			while(b < s.y) make(a, b+1);
			if(s == PII(i,j)) break;
			if(i != s.x && j != s.y){
				while(a > i) make(a-1, b);
				while(b > j) make(a, b-1);
			}else{
				if(i == s.x){
					make(a+1, b);
					while(b > j) make(a, b-1);
					make(a-1, b);
				}else{
					if(j == 0) make(a, b+1); else make(a, b-1);
					while(a > i) make(a-1, b);
					if(j == 0) make(a, b-1); else make(a, b+1);
				}
			}
		}
	}
	FWD(j,0,m-1){
		int i = n-2;
		//printf("setting %d %d and %d %d\n", i, j, i+1, j);
		FWD(r,0,2){
			//printf("setting %d %d at %d %d\n", i+1-r, j, i, j+r);
			while(b < j+r) make(a, b+1);
			while(a > i) make(a-1, b);
			while(b > j+r) make(a, b-1);
			//printf("grab at %d %d\n", a, b);
			PII s = PII(i,j+r);
			//printf("s %d %d\n", i, j+r);
			FWD(p,0,n) FWD(q,0,m) if(PII(p,q) > s && source[p][q] == target[i+1-r][j])
				s = PII(p,q);
			//printf("possibility at %d %d\n", s.x, s.y);
			//printf("source:\n");
			//FWD(_i,0,n){
			//	FWD(_j,0,n) printf("%d ", source[_i][_j]);
			//	printf("\n");
			//}
			if(s == PII(i,j+r)){
				printf("-1\n");
				return 0;
			}
			for(;;){
				while(a < s.x) make(a+1, b);
				if(b == s.y)
					--s.x;
				else
					--s.y;
				while(b < s.y) make(a, b+1);
				if(s == PII(i,j+r)) break;
				if(i != s.x && j != s.y){
					while(a > i) make(a-1, b);
					while(b > j) make(a, b-1);
				}else{
					if(i == s.x){
						make(a+1, b);
						while(b > j) make(a, b-1);
						make(a-1, b);
					}else{
						if(j == 0) make(a, b+1); else make(a, b-1);
						while(a > i) make(a-1, b);
						if(j == 0) make(a, b-1); else make(a, b+1);
					}
				}
			}
			//printf("grab at %d %d\n", a, b);
			//printf("source:\n");
			//FWD(_i,0,n){
			//	FWD(_j,0,n) printf("%d ", source[_i][_j]);
			//	printf("\n");
			//}
		}
		if(a == i) make(a+1, b);
		while(b > j) make(a, b-1);
		make(a-1, b);
		make(a, b+1);
		//printf("source:\n");
		//FWD(_i,0,n){
		//	FWD(_j,0,n) printf("%d ", source[_i][_j]);
		//	printf("\n");
		//}
		//printf("grab at %d %d\n", a, b);
	}
	check();
	if(a == n-1) make(a-1, b); else make(a+1, b);
	//printf("grab at %d %d\n", a, b);
	//printf("source:\n");
	//FWD(_i,0,n){
	//	FWD(_j,0,n) printf("%d ", source[_i][_j]);
	//	printf("\n");
	//}
	check();
	printf("-1\n");
	return 0;
}


#include <bits/stdc++.h>
#define REP(a,b) for(int a=0; a<(b); ++a)
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define FWDS(a,b,c,d) for(int a=(b); a<(c); a+=d)
#define BCK(a,b,c) for(int a=(b); a>(c); --a)
#define x first
#define y second
#define pb push_back
#define re real()
#define im imag()

using namespace std;

typedef pair<int, int> PII;

int n, m, a, b;
int tmp[33][33];
int source[33][33];
int target[33][33];
PII prv[33][33];
bool block[33][33];
vector<PII> R;

int dx[] = {-1,-1,-1,0,0,1,1,1};
int dy[] = {-1,0,1,-1,1,-1,0,1};

void save(){
	FWD(i,0,n) FWD(j,0,m) tmp[i][j] = source[i][j];
}

void load(){
	R.clear();
	FWD(i,0,n) FWD(j,0,m) source[i][j] = tmp[i][j];
}

void check(){
	FWD(i,0,n) FWD(j,0,m) if(source[i][j] != target[i][j]) return;
	printf("%d\n", (int)R.size()-1);
	for(PII r : R) printf("%d %d\n", r.x+1, r.y+1);
	exit(0);
}

void make(int x, int y){
	swap(source[R.back().x][R.back().y], source[x][y]);
	R.push_back(PII(x,y));
	a = x; b = y;
}

bool in(int x, int y){
	return 0 <= x && x < n && 0 <= y && y < m && !block[x][y];
}

void path(int x, int y){
	//printf("path %d %d\n", x, y);
	//printf("grab %d %d\n", a, b);
	FWD(i,0,n) FWD(j,0,m) prv[i][j] = PII(-1,-1);
	//FWD(i,0,n){
	//	FWD(j,0,n) printf("%d", block[i][j]);
	//	printf("\n");
	//}
	queue<PII> Q;
	Q.push(PII(a,b));
	PII c = PII(x, y);
	while(!Q.empty()){
		x = Q.front().x;
		y = Q.front().y;
		Q.pop();
		FWD(d,0,8){
			int nx = x+dx[d]; int ny = y+dy[d];
			if(in(nx, ny) && prv[nx][ny] == PII(-1,-1)){
				prv[nx][ny] = PII(x,y);
				Q.push(PII(nx, ny));
			}
		}
	}
	//printf("half done\n");
	stack<PII> S;
	while(c != PII(a,b)){
		S.push(c);
		c = prv[c.x][c.y];
	}
	while(!S.empty()){
		make(S.top().x, S.top().y);
		S.pop();
	}
	//printf("grab %d %d\n", a, b);
}

void setp(int i, int j){
	//printf("grab %d %d\n", a, b);
	//printf("setp %d %d\n", i, j);
	path(i, j);
	PII s = PII(i,j);
	FWD(p,0,n) FWD(q,0,n) if(PII(p,q) > s && source[p][q] == target[i][j]) s = PII(p,q);
	if(s == PII(i,j)){
		printf("-1\n");
		exit(0);
	}
	for(;;){
		path(s.x, s.y);
		s = R[R.size()-2];
		if(PII(i,j) == s) break;
		block[s.x][s.y] = 1;
		path(i, j);
		block[s.x][s.y] = 0;
	}
	block[i][j] = 1;
}

int main(){
	scanf("%d %d", &n, &m);
	FWD(i,0,n) FWD(j,0,m) scanf("%d", &source[i][j]);
	FWD(i,0,n) FWD(j,0,m) scanf("%d", &target[i][j]);
	save();
	if(n == 1 || m == 1){
		FWD(s,0,max(n,m)){
			for(int d=-1; d<=1; d+=2){
				load();
				R.push_back(PII(n==1?0:s,n==1?s:0));
				for(int i=s+d;-1<i&&i<max(n,m);i+=d){
					make(n==1?0:i,n==1?i:0);
					check();
				}
			}
		}
		printf("-1\n");
		return 0;
	}
	FWD(i,0,n) FWD(j,0,m) if(source[i][j] == target[n-1][m-1]) a = i, b = j;
	R.push_back(PII(a,b));
	FWD(i,0,n-2)
		FWD(j,0,m)
			setp(i, j);
	FWD(j,0,m-1){
		setp(n-2,j);
		setp(n-1,j);
	}
	check();
	if(a == n-1)
		make(a-1, b);
	else
		make(a+1, b);
	check();
	printf("-1\n");
	return 0;
}


#include <bits/stdc++.h>
#define REP(a,b) for(int a=0; a<(b); ++a)
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define FWDS(a,b,c,d) for(int a=(b); a<(c); a+=d)
#define BCK(a,b,c) for(int a=(b); a>(c); --a)
#define x first
#define y second
#define pb push_back
#define re real()
#define im imag()

using namespace std;

typedef pair<int, int> PII;

int n, m, a, b;
int tmp[33][33];
int source[33][33];
int target[33][33];
PII prv[33][33];
bool block[33][33];
vector<PII> R;

int dx[] = {-1,-1,-1,0,0,1,1,1};
int dy[] = {-1,0,1,-1,1,-1,0,1};

void save(){
	FWD(i,0,n) FWD(j,0,m) tmp[i][j] = source[i][j];
}

void load(){
	R.clear();
	FWD(i,0,n) FWD(j,0,m) source[i][j] = tmp[i][j];
}

void check(){
	FWD(i,0,n) FWD(j,0,m) if(source[i][j] != target[i][j]) return;
	printf("%d\n", (int)R.size()-1);
	for(PII r : R) printf("%d %d\n", r.x+1, r.y+1);
	exit(0);
}

void make(int x, int y){
	swap(source[R.back().x][R.back().y], source[x][y]);
	R.push_back(PII(x,y));
	a = x; b = y;
}

bool in(int x, int y){
	return 0 <= x && x < n && 0 <= y && y < m && !block[x][y];
}

void path(int x, int y){
	//printf("path %d %d\n", x, y);
	//printf("grab %d %d\n", a, b);
	FWD(i,0,n) FWD(j,0,m) prv[i][j] = PII(-1,-1);
	queue<PII> Q;
	Q.push(PII(a,b));
	PII c = PII(x, y);
	while(!Q.empty()){
		x = Q.front().x;
		y = Q.front().y;
		Q.pop();
		FWD(d,0,8){
			int nx = x+dx[d]; int ny = y+dy[d];
			if(in(nx, ny) && prv[nx][ny] == PII(-1,-1)){
				prv[nx][ny] = PII(x,y);
				Q.push(PII(nx, ny));
			}
		}
	}
	//printf("half done\n");
	stack<PII> S;
	while(c != PII(a,b)){
		S.push(c);
		c = prv[c.x][c.y];
	}
	while(!S.empty()){
		make(S.top().x, S.top().y);
		S.pop();
	}
	//printf("grab %d %d\n", a, b);
}

void setp(int i, int j){
	//printf("grab %d %d\n", a, b);
	//printf("setp %d %d\n", i, j);
	path(i, j);
	for(;;){
		PII s = PII(i,j);
		FWD(p,0,n) FWD(q,0,n) if(PII(p,q) > s && source[p][q] == target[i][j]){
			s = PII(p,q);
			goto found;
		}
		printf("-1\n");
		exit(0);
	found:
		//printf("pos %d %d\n", s.x, s.y);
		path(s.x, s.y);
		s = R[R.size()-2];
		if(PII(i,j) == s) break;
		block[s.x][s.y] = 1;
		path(i, j);
		block[s.x][s.y] = 0;
	}
	block[i][j] = 1;
}

int main(){
	scanf("%d %d", &n, &m);
	FWD(i,0,n) FWD(j,0,m) scanf("%d", &source[i][j]);
	FWD(i,0,n) FWD(j,0,m) scanf("%d", &target[i][j]);
	save();
	if(n == 1 || m == 1){
		FWD(s,0,max(n,m)){
			for(int d=-1; d<=1; d+=2){
				load();
				R.push_back(PII(n==1?0:s,n==1?s:0));
				for(int i=s+d;-1<i&&i<max(n,m);i+=d){
					make(n==1?0:i,n==1?i:0);
					check();
				}
			}
		}
		printf("-1\n");
		return 0;
	}
	FWD(i,0,n) FWD(j,0,m) if(source[i][j] == target[n-1][m-1]) a = i, b = j;
	R.push_back(PII(a,b));
	FWD(i,0,n-2)
		FWD(j,0,m)
			setp(i, j);
	FWD(j,0,m-1){
		setp(n-2,j);
		setp(n-1,j);
	}
	check();
	if(a == n-1)
		make(a-1, b);
	else
		make(a+1, b);
	check();
	printf("-1\n");
	return 0;
}


#include <bits/stdc++.h>
#define REP(a,b) for(int a=0; a<(b); ++a)
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define FWDS(a,b,c,d) for(int a=(b); a<(c); a+=d)
#define BCK(a,b,c) for(int a=(b); a>(c); --a)
#define x first
#define y second
#define pb push_back
#define re real()
#define im imag()

using namespace std;

typedef pair<int, int> PII;

int n, m, a, b;
int tmp[33][33];
int source[33][33];
int target[33][33];
PII prv[33][33];
bool block[33][33];
vector<PII> R;

int dx[] = {-1,-1,-1,0,0,1,1,1};
int dy[] = {-1,0,1,-1,1,-1,0,1};

void save(){
	FWD(i,0,n) FWD(j,0,m) tmp[i][j] = source[i][j];
}

void load(){
	R.clear();
	FWD(i,0,n) FWD(j,0,m) source[i][j] = tmp[i][j];
}

void check(){
	FWD(i,0,n) FWD(j,0,m) if(source[i][j] != target[i][j]) return;
	printf("%d\n", (int)R.size()-1);
	for(PII r : R) printf("%d %d\n", r.x+1, r.y+1);
	exit(0);
}

void make(int x, int y){
	swap(source[R.back().x][R.back().y], source[x][y]);
	R.push_back(PII(x,y));
	a = x; b = y;
}

bool in(int x, int y){
	return 0 <= x && x < n && 0 <= y && y < m && !block[x][y];
}

void path(int x, int y){
	FWD(i,0,n) FWD(j,0,m) prv[i][j] = PII(-1,-1);
	queue<PII> Q;
	Q.push(PII(a,b));
	PII c = PII(x, y);
	while(!Q.empty()){
		x = Q.front().x;
		y = Q.front().y;
		Q.pop();
		FWD(d,0,8){
			int nx = x+dx[d]; int ny = y+dy[d];
			if(in(nx, ny) && prv[nx][ny] == PII(-1,-1)){
				prv[nx][ny] = PII(x,y);
				Q.push(PII(nx, ny));
			}
		}
	}
	stack<PII> S;
	while(c != PII(a,b)){
		S.push(c);
		c = prv[c.x][c.y];
	}
	while(!S.empty()){
		make(S.top().x, S.top().y);
		S.pop();
	}
}

void setp(int i, int j){
	path(i, j);
	PII s = PII(i,j);
	block[i][j] = 1;
	FWD(p,0,n) FWD(q,0,m) if(!block[p][q] && source[p][q] == target[i][j]) s = PII(p,q);
	block[i][j] = 0;
	if(s == PII(i,j)){
		printf("-1\n");
		exit(0);
	}
	for(;;){
		path(s.x, s.y);
		s = R[R.size()-2];
		if(PII(i,j) == s) break;
		block[s.x][s.y] = 1;
		path(i, j);
		block[s.x][s.y] = 0;
	}
	block[i][j] = 1;
}

int main(){
	scanf("%d %d", &n, &m);
	FWD(i,0,n) FWD(j,0,m) scanf("%d", &source[i][j]);
	FWD(i,0,n) FWD(j,0,m) scanf("%d", &target[i][j]);
	save();
	if(n == 1 || m == 1){
		FWD(s,0,max(n,m)){
			for(int d=-1; d<=1; d+=2){
				load();
				R.push_back(PII(n==1?0:s,n==1?s:0));
				for(int i=s+d;-1<i&&i<max(n,m);i+=d){
					make(n==1?0:i,n==1?i:0);
					check();
				}
			}
		}
		printf("-1\n");
		return 0;
	}
	FWD(i,0,n) FWD(j,0,m) if(source[i][j] == target[n-1][m-1]) a = i, b = j;
	R.push_back(PII(a,b));
	FWD(i,0,n-2)
		FWD(j,0,m)
			setp(i, j);
	FWD(j,0,m-1){
		setp(n-2,j);
		setp(n-1,j);
	}
	check();
	if(a == n-1)
		make(a-1, b);
	else
		make(a+1, b);
	check();
	printf("-1\n");
	return 0;
}


#include <bits/stdc++.h>
#define REP(a,b) for(int a=0; a<(b); ++a)
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define FWDS(a,b,c,d) for(int a=(b); a<(c); a+=d)
#define BCK(a,b,c) for(int a=(b); a>(c); --a)
#define x first
#define y second
#define pb push_back
#define re real()
#define im imag()

using namespace std;

typedef pair<int, int> PII;

int n, m, a, b;
int tmp[33][33];
int source[33][33];
int target[33][33];
PII prv[33][33];
bool block[33][33];
vector<PII> R;

int dx[] = {-1,-1,-1,0,0,1,1,1};
int dy[] = {-1,0,1,-1,1,-1,0,1};

void save(){
	FWD(i,0,n) FWD(j,0,m) tmp[i][j] = source[i][j];
}

void load(){
	R.clear();
	FWD(i,0,n) FWD(j,0,m) source[i][j] = tmp[i][j];
}

void check(){
	FWD(i,0,n) FWD(j,0,m) if(source[i][j] != target[i][j]) return;
	printf("%d\n", (int)R.size()-1);
	for(PII r : R) printf("%d %d\n", r.x+1, r.y+1);
	exit(0);
}

void make(int x, int y){
	swap(source[R.back().x][R.back().y], source[x][y]);
	R.push_back(PII(x,y));
	a = x; b = y;
}

bool in(int x, int y){
	return 0 <= x && x < n && 0 <= y && y < m && !block[x][y];
}

void path(int x, int y){
//	printf("path %d %d\n", x, y);
//	printf("grab %d %d\n", a, b);
	FWD(i,0,n) FWD(j,0,m) prv[i][j] = PII(-1,-1);
	queue<PII> Q;
	Q.push(PII(a,b));
	PII c = PII(x, y);
	while(!Q.empty()){
		x = Q.front().x;
		y = Q.front().y;
		Q.pop();
		FWD(d,0,8){
			int nx = x+dx[d]; int ny = y+dy[d];
			if(in(nx, ny) && prv[nx][ny] == PII(-1,-1)){
				prv[nx][ny] = PII(x,y);
				Q.push(PII(nx, ny));
			}
		}
	}
//	printf("half done\n");
	stack<PII> S;
	while(c != PII(a,b)){
		S.push(c);
		c = prv[c.x][c.y];
	}
	while(!S.empty()){
		make(S.top().x, S.top().y);
		S.pop();
	}
//	printf("grab %d %d\n", a, b);
}

void setp(int i, int j){
//	printf("grab %d %d\n", a, b);
//	printf("setp %d %d\n", i, j);
	path(i, j);
//	FWD(i,0,n){
//		FWD(j,0,n) printf("%d ", source[i][j]);
//		printf("\n");
//	}
	PII s = PII(i,j);
	block[i][j] = 1;
	FWD(p,0,n) FWD(q,0,n) if(!block[p][q] && source[p][q] == target[i][j]) s = PII(p,q);
	block[i][j] = 0;
	if(s == PII(i,j)){
		printf("-1\n");
		exit(0);
	}
	for(;;){
//		printf("pos %d %d\n", s.x, s.y);
		path(s.x, s.y);
		s = R[R.size()-2];
		if(PII(i,j) == s) break;
		block[s.x][s.y] = 1;
		path(i, j);
		block[s.x][s.y] = 0;
	}
	block[i][j] = 1;
}

int main(){
	scanf("%d %d", &n, &m);
	FWD(i,0,n) FWD(j,0,m) scanf("%d", &source[i][j]);
	FWD(i,0,n) FWD(j,0,m) scanf("%d", &target[i][j]);
	save();
	if(n == 1 || m == 1){
		FWD(s,0,max(n,m)){
			for(int d=-1; d<=1; d+=2){
				load();
				R.push_back(PII(n==1?0:s,n==1?s:0));
				for(int i=s+d;-1<i&&i<max(n,m);i+=d){
					make(n==1?0:i,n==1?i:0);
					check();
				}
			}
		}
		printf("-1\n");
		return 0;
	}
	FWD(i,0,n) FWD(j,0,m) if(source[i][j] == target[n-1][m-1]) a = i, b = j;
	R.push_back(PII(a,b));
	FWD(i,0,n-2)
		FWD(j,0,m)
			setp(i, j);
	FWD(j,0,m-1){
		setp(n-2,j);
		setp(n-1,j);
	}
	check();
	if(a == n-1)
		make(a-1, b);
	else
		make(a+1, b);
	check();
	printf("-1\n");
	return 0;
}


#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <map>

using namespace std;

const int MAX = 1<<5;

struct str {
    int red, stup;
    str (int red, int stup) : red(red), stup(stup) {}
    str () {}
};

bool operator == (str a, str b) {
    return a.red == b.red && a.stup == b.stup;
}

int brred, brstup, polje[MAX][MAX], kraj[MAX][MAX], k1[8] = {-1, -1, 0, 1, 1, 1, 0, -1}, k2[8] = {0, 1, 1, 1, 0, -1, -1, -1}, tmpred, tmpstup;
int taken[MAX][MAX], bio[MAX][MAX], odakle1[MAX][MAX], odakle2[MAX][MAX], polje2[MAX][MAX];
queue <str> Q;
vector <str> R;
map <int, int> M;

void Pomak(int smjer)
{
    int nred, nstup;

    nred = tmpred + k1[smjer];
    nstup = tmpstup + k2[smjer];

    swap(polje[tmpred][tmpstup], polje[nred][nstup]);
    R.push_back(str(nred, nstup));
    tmpred = nred;
    tmpstup = nstup;
}

str Nadi(int val)
{
    int i, j;

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++)
            if (!taken[i][j] && polje[i][j] == val)
                return str(i, j);

    return str(-1, -1);
}

int Moze(int red, int stup)
{
    if (red < 1 || stup < 1 || red > brred || stup > brstup || taken[red][stup] || bio[red][stup])
        return 0;
    return 1;
}

void BfsPom(str to)
{
    int i, nred, nstup, da=0;
    str from, tmp;

    from = str(tmpred, tmpstup);

    for (; !Q.empty(); Q.pop());
    memset(bio, 0, sizeof bio);

    Q.push(to);
    bio[to.red][to.stup] = 1;

    for (; !Q.empty(); ) {
        tmp = Q.front();
        Q.pop();

        if (tmp == from) {
            da = 1;
            break;
        }

        for (i=0; i<8; i++) {
            nred = tmp.red + k1[i];
            nstup = tmp.stup + k2[i];
            if (Moze(nred, nstup)) {
                Q.push(str(nred, nstup));
                bio[nred][nstup] = 1;
                odakle1[nred][nstup] = (i+4) % 8;
            }
        }
    }

    for (; tmpred != to.red || tmpstup != to.stup;)
        Pomak(odakle1[tmpred][tmpstup]);

    if (!da)
        printf("NIJE NASO BFSPOM\n");
}

void Bfs(str from, str to)
{
    int i, nred, nstup, da=0;
    str tmp, slj;

    for (; !Q.empty(); Q.pop());
    memset(bio, 0, sizeof bio);

    Q.push(to);
    bio[to.red][to.stup] = 1;

    for (; !Q.empty(); ) {
        tmp = Q.front();
        Q.pop();

        if (tmp == from) {
            da = 1;
            break;
        }

        for (i=0; i<8; i++) {
            nred = tmp.red + k1[i];
            nstup = tmp.stup + k2[i];
            if (Moze(nred, nstup)) {
                Q.push(str(nred, nstup));
                bio[nred][nstup] = 1;
                odakle2[nred][nstup] = (i+4) % 8;
            }
        }
    }

    for (tmp=from; !(tmp == to);) {
        taken[tmp.red][tmp.stup] = 1;
        slj = str(tmp.red + k1[odakle2[tmp.red][tmp.stup]], tmp.stup + k2[odakle2[tmp.red][tmp.stup]]);
        BfsPom(slj);
        Pomak((4 + odakle2[tmp.red][tmp.stup]) % 8);
        taken[tmp.red][tmp.stup] = 0;
        tmp = slj;
    }

    if (!da)
        printf("NIJE NASO BFS\n");
}

void IspisPot()
{
    int i;

    printf("%u\n", R.size() - 1);
    for (i=0; (unsigned) i<R.size(); i++)
        printf("%d %d\n", R[i].red, R[i].stup);
}

void IspisPloce(char s[10], int p[MAX][MAX])
{
    int i, j;

    printf("%s\n", s);
    for (i=1; i<=brred; i++) {
        for (j=1; j<=brstup; j++)
            printf("%d ", p[i][j]);
        printf("\n");
    }
    printf("\n");
}

void RijesiKraj()
{
    int sm, nred, nstup, i, j, ne;

    memset(bio, 0, sizeof bio);

    for (;;) {
        ne = 0;
        for (i=brred-1; i<=brred; i++)
            for (j=brstup-1; j<=brstup; j++)
                if (polje[i][j] != kraj[i][j])
                    ne = 1;
        if (!ne)
            return;
        sm = rand() % 8;
        nred = tmpred + k1[sm];
        nstup = tmpstup + k2[sm];
        if (Moze(nred, nstup))
            Pomak(sm);

        //IspisPloce("POLJE", polje);
        /*IspisPloce("TAKEN", taken);
        printf("MOZE %d %d\n", bio[2][2], Moze(2, 2));
        system("pause");*/
    }
}

int main()
{
    int i, j, k, sm, da=0, raz;
    str pocetak;
    map <int, int> :: iterator it;

    scanf("%d%d", &brred, &brstup);

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++) {
            scanf("%d", &polje[i][j]);
            M[polje[i][j]]++;
        }

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++) {
            scanf("%d", &kraj[i][j]);
            M[kraj[i][j]]--;
        }

    for (it=M.begin(); it!=M.end(); it++)
        if (it->second) {
            printf("-1\n");
            return 0;
        }

    if (brred > 1 && brstup > 1) {
        pocetak = Nadi(kraj[brred][brstup]);
        tmpred = pocetak.red;
        tmpstup = pocetak.stup;

        R.push_back(pocetak);

        for (i=1; i<=brred-2; i++)
            for (j=1; j<=brstup; j++) {
                Bfs(Nadi(kraj[i][j]), str(i, j));
                taken[i][j] = 1;
                //IspisPloce("POLJE", polje);
                //IspisPloce("TAKEN", taken);
            }

        for (j=1; j<=brstup-2; j++)
            for (i=brred-1; i<=brred; i++) {
                //printf("KKK %d %d %d %d\n", Nadi(kraj[i][j]).red, Nadi(kraj[i][j]).stup, i, j);
                Bfs(Nadi(kraj[i][j]), str(i, j));
                taken[i][j] = 1;
                //IspisPloce("POLJE", polje);
                //IspisPloce("TAKEN", taken);
            }

        RijesiKraj();
        da = 1;
        IspisPot();
    }
    else if (brred == 1) {
        memcpy(polje2, polje, sizeof polje);
        tmpred = 1;
        for (i=1; i<=brstup; i++) {
            for (j=1; j<=brstup; j++) {
                memcpy(polje, polje2, sizeof polje);
                R.clear();
                tmpstup = i;
                if (j > i)
                    sm = 2;
                else
                    sm = 6;

                R.push_back(str(1, i));
                for (; tmpstup != j; Pomak(sm));

                for (raz=0, k=1; k<=brstup; k++)
                    if (polje[1][k] != kraj[1][k])
                        raz = 1;

                if (!raz) {
                    da = 1;
                    IspisPot();
                    break;
                }
            }
            if (da)
                break;
        }
    }
    else {
        memcpy(polje2, polje, sizeof polje);
        tmpstup = 1;
        for (i=1; i<=brred; i++) {
            for (j=1; j<=brred; j++) {
                memcpy(polje, polje2, sizeof polje);
                R.clear();
                tmpred = i;
                if (j > i)
                    sm = 4;
                else
                    sm = 0;

                R.push_back(str(i, 1));
                for (; tmpred != j; Pomak(sm));

                for (raz=0, k=1; k<=brred; k++)
                    if (polje[k][1] != kraj[k][1])
                        raz = 1;

                if (!raz) {
                    da = 1;
                    IspisPot();
                    break;
                }
            }
            if (da)
                break;
        }
    }

    if (!da)
        printf("-1\n");

    return 0;
}


#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <map>

using namespace std;

const int MAX = 1<<5;

struct str {
    int red, stup;
    str (int red, int stup) : red(red), stup(stup) {}
    str () {}
};

bool operator == (str a, str b) {
    return a.red == b.red && a.stup == b.stup;
}

int brred, brstup, polje[MAX][MAX], kraj[MAX][MAX], k1[8] = {-1, -1, 0, 1, 1, 1, 0, -1}, k2[8] = {0, 1, 1, 1, 0, -1, -1, -1}, tmpred, tmpstup;
int taken[MAX][MAX], bio[MAX][MAX], odakle1[MAX][MAX], odakle2[MAX][MAX], polje2[MAX][MAX];
queue <str> Q;
vector <str> R;
map <int, int> M;

void Pomak(int smjer)
{
    int nred, nstup;

    nred = tmpred + k1[smjer];
    nstup = tmpstup + k2[smjer];

    swap(polje[tmpred][tmpstup], polje[nred][nstup]);
    R.push_back(str(nred, nstup));
    tmpred = nred;
    tmpstup = nstup;
}

str Nadi(int val)
{
    int i, j;

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++)
            if (!taken[i][j] && polje[i][j] == val)
                return str(i, j);

    return str(-1, -1);
}

int Moze(int red, int stup)
{
    if (red < 1 || stup < 1 || red > brred || stup > brstup || taken[red][stup] || bio[red][stup])
        return 0;
    return 1;
}

void BfsPom(str to)
{
    int i, nred, nstup, da=0;
    str from, tmp;

    from = str(tmpred, tmpstup);

    for (; !Q.empty(); Q.pop());
    memset(bio, 0, sizeof bio);

    Q.push(to);
    bio[to.red][to.stup] = 1;

    for (; !Q.empty(); ) {
        tmp = Q.front();
        Q.pop();

        if (tmp == from) {
            da = 1;
            break;
        }

        for (i=0; i<8; i++) {
            nred = tmp.red + k1[i];
            nstup = tmp.stup + k2[i];
            if (Moze(nred, nstup)) {
                Q.push(str(nred, nstup));
                bio[nred][nstup] = 1;
                odakle1[nred][nstup] = (i+4) % 8;
            }
        }
    }

    for (; tmpred != to.red || tmpstup != to.stup;)
        Pomak(odakle1[tmpred][tmpstup]);

    if (!da)
        printf("NIJE NASO BFSPOM\n");
}

void Bfs(str from, str to)
{
    int i, nred, nstup, da=0;
    str tmp, slj;

    for (; !Q.empty(); Q.pop());
    memset(bio, 0, sizeof bio);

    Q.push(to);
    bio[to.red][to.stup] = 1;

    for (; !Q.empty(); ) {
        tmp = Q.front();
        Q.pop();

        if (tmp == from) {
            da = 1;
            break;
        }

        for (i=0; i<8; i++) {
            nred = tmp.red + k1[i];
            nstup = tmp.stup + k2[i];
            if (Moze(nred, nstup)) {
                Q.push(str(nred, nstup));
                bio[nred][nstup] = 1;
                odakle2[nred][nstup] = (i+4) % 8;
            }
        }
    }

    for (tmp=from; !(tmp == to);) {
        taken[tmp.red][tmp.stup] = 1;
        slj = str(tmp.red + k1[odakle2[tmp.red][tmp.stup]], tmp.stup + k2[odakle2[tmp.red][tmp.stup]]);
        BfsPom(slj);
        Pomak((4 + odakle2[tmp.red][tmp.stup]) % 8);
        taken[tmp.red][tmp.stup] = 0;
        tmp = slj;
    }

    if (!da)
        printf("NIJE NASO BFS\n");
}

void IspisPot()
{
    int i;

    printf("%u\n", R.size() - 1);
    for (i=0; (unsigned) i<R.size(); i++)
        printf("%d %d\n", R[i].red, R[i].stup);
}

void IspisPloce(char s[10], int p[MAX][MAX])
{
    int i, j;

    printf("%s\n", s);
    for (i=1; i<=brred; i++) {
        for (j=1; j<=brstup; j++)
            printf("%d ", p[i][j]);
        printf("\n");
    }
    printf("\n");
}

int Done()
{
    int i, j;

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++)
            if (polje[i][j] != kraj[i][j])
                return 0;
    return 1;
}
void RijesiKraj()
{
    int sm, nred, nstup, i, j, ne;

    memset(bio, 0, sizeof bio);

    for (;;) {
        ne = 0;
        for (i=brred-1; i<=brred; i++)
            for (j=brstup-1; j<=brstup; j++)
                if (polje[i][j] != kraj[i][j])
                    ne = 1;
        if (!ne)
            return;
        sm = rand() % 8;
        nred = tmpred + k1[sm];
        nstup = tmpstup + k2[sm];
        if (Moze(nred, nstup))
            Pomak(sm);

        //IspisPloce("POLJE", polje);
        /*IspisPloce("TAKEN", taken);
        printf("MOZE %d %d\n", bio[2][2], Moze(2, 2));
        system("pause");*/
    }
}

int main()
{
    int i, j, sm, da=0;
    str pocetak;
    map <int, int> :: iterator it;

    scanf("%d%d", &brred, &brstup);

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++) {
            scanf("%d", &polje[i][j]);
            M[polje[i][j]]++;
        }

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++) {
            scanf("%d", &kraj[i][j]);
            M[kraj[i][j]]--;
        }

    for (it=M.begin(); it!=M.end(); it++)
        if (it->second) {
            printf("-1\n");
            return 0;
        }

    if (brred > 1 && brstup > 1) {
        pocetak = Nadi(kraj[brred][brstup]);
        tmpred = pocetak.red;
        tmpstup = pocetak.stup;

        R.push_back(pocetak);

        for (i=1; i<=brred-2; i++)
            for (j=1; j<=brstup; j++) {
                Bfs(Nadi(kraj[i][j]), str(i, j));
                taken[i][j] = 1;
                if (Done()) {
                    IspisPot();
                    return 0;
                }
                //IspisPloce("POLJE", polje);
                //IspisPloce("TAKEN", taken);
            }

        /*printf("DA\n");
        IspisPloce("POLJE", polje);*/

        for (j=1; j<=brstup-2; j++)
            for (i=brred-1; i<=brred; i++) {
                //printf("KKK %d %d %d %d\n", Nadi(kraj[i][j]).red, Nadi(kraj[i][j]).stup, i, j);
                Bfs(Nadi(kraj[i][j]), str(i, j));
                taken[i][j] = 1;
                if (Done()) {
                    IspisPot();
                    return 0;
                }
                //IspisPloce("POLJE", polje);
                //IspisPloce("TAKEN", taken);
            }

        //printf("DA\n");

        RijesiKraj();
        da = 1;
        IspisPot();
    }
    else if (brred == 1) {
        memcpy(polje2, polje, sizeof polje);
        tmpred = 1;
        for (i=1; i<=brstup; i++) {
            for (j=1; j<=brstup; j++) {
                memcpy(polje, polje2, sizeof polje);
                R.clear();
                tmpstup = i;
                if (j > i)
                    sm = 2;
                else
                    sm = 6;

                R.push_back(str(1, i));
                for (; tmpstup != j; Pomak(sm));

                if (Done()) {
                    da = 1;
                    IspisPot();
                    break;
                }
            }
            if (da)
                break;
        }
    }
    else {
        memcpy(polje2, polje, sizeof polje);
        tmpstup = 1;
        for (i=1; i<=brred; i++) {
            for (j=1; j<=brred; j++) {
                memcpy(polje, polje2, sizeof polje);
                R.clear();
                tmpred = i;
                if (j > i)
                    sm = 4;
                else
                    sm = 0;

                R.push_back(str(i, 1));
                for (; tmpred != j; Pomak(sm));

                if (Done()) {
                    da = 1;
                    IspisPot();
                    break;
                }
            }
            if (da)
                break;
        }
    }

    if (!da)
        printf("-1\n");

    return 0;
}


#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <map>

using namespace std;

const int MAX = 1<<5;

struct str {
    int red, stup;
    str (int red, int stup) : red(red), stup(stup) {}
    str () {}
};

bool operator == (str a, str b) {
    return a.red == b.red && a.stup == b.stup;
}

int brred, brstup, polje[MAX][MAX], kraj[MAX][MAX], k1[8] = {-1, -1, 0, 1, 1, 1, 0, -1}, k2[8] = {0, 1, 1, 1, 0, -1, -1, -1}, tmpred, tmpstup;
int taken[MAX][MAX], bio[MAX][MAX], odakle1[MAX][MAX], odakle2[MAX][MAX], polje2[MAX][MAX];
queue <str> Q;
vector <str> R;
map <int, int> M;

void Pomak(int smjer)
{
    int nred, nstup;

    nred = tmpred + k1[smjer];
    nstup = tmpstup + k2[smjer];

    swap(polje[tmpred][tmpstup], polje[nred][nstup]);
    R.push_back(str(nred, nstup));
    tmpred = nred;
    tmpstup = nstup;
}

str Nadi(int val)
{
    int i, j;

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++)
            if (!taken[i][j] && polje[i][j] == val && (i != tmpred || j != tmpstup))
                return str(i, j);

    return str(-1, -1);
}

int Moze(int red, int stup)
{
    if (red < 1 || stup < 1 || red > brred || stup > brstup || taken[red][stup] || bio[red][stup])
        return 0;
    return 1;
}

void BfsPom(str to)
{
    int i, nred, nstup, da=0;
    str from, tmp;

    from = str(tmpred, tmpstup);

    for (; !Q.empty(); Q.pop());
    memset(bio, 0, sizeof bio);

    Q.push(to);
    bio[to.red][to.stup] = 1;

    for (; !Q.empty(); ) {
        tmp = Q.front();
        Q.pop();

        if (tmp == from) {
            da = 1;
            break;
        }

        for (i=0; i<8; i++) {
            nred = tmp.red + k1[i];
            nstup = tmp.stup + k2[i];
            if (Moze(nred, nstup)) {
                Q.push(str(nred, nstup));
                bio[nred][nstup] = 1;
                odakle1[nred][nstup] = (i+4) % 8;
            }
        }
    }

    for (; tmpred != to.red || tmpstup != to.stup;)
        Pomak(odakle1[tmpred][tmpstup]);

    if (!da)
        printf("NIJE NASO BFSPOM\n");
}

void Bfs(str from, str to)
{
    int i, nred, nstup, da=0;
    str tmp, slj;

    for (; !Q.empty(); Q.pop());
    memset(bio, 0, sizeof bio);

    Q.push(to);
    bio[to.red][to.stup] = 1;

    for (; !Q.empty(); ) {
        tmp = Q.front();
        Q.pop();

        if (tmp == from) {
            da = 1;
            break;
        }

        for (i=0; i<8; i++) {
            nred = tmp.red + k1[i];
            nstup = tmp.stup + k2[i];
            if (Moze(nred, nstup)) {
                Q.push(str(nred, nstup));
                bio[nred][nstup] = 1;
                odakle2[nred][nstup] = (i+4) % 8;
            }
        }
    }

    for (tmp=from; !(tmp == to);) {
        taken[tmp.red][tmp.stup] = 1;
        slj = str(tmp.red + k1[odakle2[tmp.red][tmp.stup]], tmp.stup + k2[odakle2[tmp.red][tmp.stup]]);
        BfsPom(slj);
        Pomak((4 + odakle2[tmp.red][tmp.stup]) % 8);
        taken[tmp.red][tmp.stup] = 0;
        tmp = slj;
    }

    if (!da)
        printf("NIJE NASO BFS\n");
}

void IspisPot()
{
    int i;

    printf("%u\n", R.size() - 1);
    for (i=0; (unsigned) i<R.size(); i++)
        printf("%d %d\n", R[i].red, R[i].stup);
}

void IspisPloce(char s[10], int p[MAX][MAX])
{
    int i, j;

    printf("%s\n", s);
    for (i=1; i<=brred; i++) {
        for (j=1; j<=brstup; j++)
            printf("%d ", p[i][j]);
        printf("\n");
    }
    printf("\n");
}

int Done()
{
    int i, j;

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++)
            if (polje[i][j] != kraj[i][j])
                return 0;
    return 1;
}
void RijesiKraj()
{
    int sm, nred, nstup, i, j, ne;

    memset(bio, 0, sizeof bio);

    for (;;) {
        ne = 0;
        for (i=brred-1; i<=brred; i++)
            for (j=brstup-1; j<=brstup; j++)
                if (polje[i][j] != kraj[i][j])
                    ne = 1;
        if (!ne)
            return;
        sm = rand() % 8;
        nred = tmpred + k1[sm];
        nstup = tmpstup + k2[sm];
        if (Moze(nred, nstup))
            Pomak(sm);
    }
}

int main()
{
    int i, j, sm, da=0;
    str pocetak;
    map <int, int> :: iterator it;

    scanf("%d%d", &brred, &brstup);

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++) {
            scanf("%d", &polje[i][j]);
            M[polje[i][j]]++;
        }

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++) {
            scanf("%d", &kraj[i][j]);
            M[kraj[i][j]]--;
        }

    for (it=M.begin(); it!=M.end(); it++)
        if (it->second) {
            printf("-1\n");
            return 0;
        }

    if (brred > 1 && brstup > 1) {
        pocetak = Nadi(kraj[brred][brstup]);
        tmpred = pocetak.red;
        tmpstup = pocetak.stup;

        R.push_back(pocetak);

        for (i=1; i<=brred-2; i++) {
            for (j=1; j<=brstup; j++) {
                Bfs(Nadi(kraj[i][j]), str(i, j));
                taken[i][j] = 1;
            }
        }

        for (j=1; j<=brstup-2; j++) {
            for (i=brred-1; i<=brred; i++) {
                Bfs(Nadi(kraj[i][j]), str(i, j));
                taken[i][j] = 1;
            }
        }

        RijesiKraj();
        da = 1;
        IspisPot();
    }
    else if (brred == 1) {
        memcpy(polje2, polje, sizeof polje);
        tmpred = 1;
        for (i=1; i<=brstup; i++) {
            for (j=1; j<=brstup; j++) {
                memcpy(polje, polje2, sizeof polje);
                R.clear();
                tmpstup = i;
                if (j > i)
                    sm = 2;
                else
                    sm = 6;

                R.push_back(str(1, i));
                for (; tmpstup != j; Pomak(sm));

                if (Done()) {
                    da = 1;
                    IspisPot();
                    break;
                }
            }
            if (da)
                break;
        }
    }
    else {
        memcpy(polje2, polje, sizeof polje);
        tmpstup = 1;
        for (i=1; i<=brred; i++) {
            for (j=1; j<=brred; j++) {
                memcpy(polje, polje2, sizeof polje);
                R.clear();
                tmpred = i;
                if (j > i)
                    sm = 4;
                else
                    sm = 0;

                R.push_back(str(i, 1));
                for (; tmpred != j; Pomak(sm));

                if (Done()) {
                    da = 1;
                    IspisPot();
                    break;
                }
            }
            if (da)
                break;
        }
    }

    if (!da)
        printf("-1\n");

    return 0;
}


#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <map>

using namespace std;

const int MAX = 1<<5;

struct str {
    int red, stup;
    str (int red, int stup) : red(red), stup(stup) {}
    str () {}
};

bool operator == (str a, str b) {
    return a.red == b.red && a.stup == b.stup;
}

int brred, brstup, polje[MAX][MAX], kraj[MAX][MAX], k1[8] = {-1, -1, 0, 1, 1, 1, 0, -1}, k2[8] = {0, 1, 1, 1, 0, -1, -1, -1}, tmpred, tmpstup;
int taken[MAX][MAX], bio[MAX][MAX], odakle1[MAX][MAX], odakle2[MAX][MAX], polje2[MAX][MAX];
queue <str> Q;
vector <str> R;
map <int, int> M;

void Pomak(int smjer)
{
    int nred, nstup;

    nred = tmpred + k1[smjer];
    nstup = tmpstup + k2[smjer];

    swap(polje[tmpred][tmpstup], polje[nred][nstup]);
    R.push_back(str(nred, nstup));
    tmpred = nred;
    tmpstup = nstup;
}

str Nadi(int val)
{
    int i, j;

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++)
            if (!taken[i][j] && polje[i][j] == val && (i != tmpred || j != tmpstup))
                return str(i, j);

    return str(-1, -1);
}

int Moze(int red, int stup)
{
    if (red < 1 || stup < 1 || red > brred || stup > brstup || taken[red][stup] || bio[red][stup])
        return 0;
    return 1;
}

void BfsPom(str to)
{
    int i, nred, nstup, da=0;
    str from, tmp;

    from = str(tmpred, tmpstup);

    for (; !Q.empty(); Q.pop());
    memset(bio, 0, sizeof bio);

    Q.push(to);
    bio[to.red][to.stup] = 1;

    for (; !Q.empty(); ) {
        tmp = Q.front();
        Q.pop();

        if (tmp == from) {
            da = 1;
            break;
        }

        for (i=0; i<8; i++) {
            nred = tmp.red + k1[i];
            nstup = tmp.stup + k2[i];
            if (Moze(nred, nstup)) {
                Q.push(str(nred, nstup));
                bio[nred][nstup] = 1;
                odakle1[nred][nstup] = (i+4) % 8;
            }
        }
    }

    for (; tmpred != to.red || tmpstup != to.stup;)
        Pomak(odakle1[tmpred][tmpstup]);

    if (!da)
        printf("NIJE NASO BFSPOM\n");
}

void Bfs(str from, str to)
{
    int i, nred, nstup, da=0;
    str tmp, slj;

    for (; !Q.empty(); Q.pop());
    memset(bio, 0, sizeof bio);

    Q.push(to);
    bio[to.red][to.stup] = 1;

    for (; !Q.empty(); ) {
        tmp = Q.front();
        Q.pop();

        if (tmp == from) {
            da = 1;
            break;
        }

        for (i=0; i<8; i++) {
            nred = tmp.red + k1[i];
            nstup = tmp.stup + k2[i];
            if (Moze(nred, nstup)) {
                Q.push(str(nred, nstup));
                bio[nred][nstup] = 1;
                odakle2[nred][nstup] = (i+4) % 8;
            }
        }
    }

    for (tmp=from; !(tmp == to);) {
        taken[tmp.red][tmp.stup] = 1;
        slj = str(tmp.red + k1[odakle2[tmp.red][tmp.stup]], tmp.stup + k2[odakle2[tmp.red][tmp.stup]]);
        BfsPom(slj);
        Pomak((4 + odakle2[tmp.red][tmp.stup]) % 8);
        taken[tmp.red][tmp.stup] = 0;
        tmp = slj;
    }

    if (!da)
        printf("NIJE NASO BFS\n");
}

void IspisPot()
{
    int i;

    printf("%u\n", R.size() - 1);
    for (i=0; (unsigned) i<R.size(); i++)
        printf("%d %d\n", R[i].red, R[i].stup);
}

void IspisPloce(char s[10], int p[MAX][MAX])
{
    int i, j;

    printf("%s\n", s);
    for (i=1; i<=brred; i++) {
        for (j=1; j<=brstup; j++)
            printf("%d ", p[i][j]);
        printf("\n");
    }
    printf("\n");
}

int Done()
{
    int i, j;

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++)
            if (polje[i][j] != kraj[i][j])
                return 0;
    return 1;
}
void RijesiKraj()
{
    int sm, nred, nstup, i, j, ne;

    memset(bio, 0, sizeof bio);

    for (;;) {
        ne = 0;
        for (i=brred-1; i<=brred; i++)
            for (j=brstup-1; j<=brstup; j++)
                if (polje[i][j] != kraj[i][j])
                    ne = 1;
        if (!ne)
            return;
        sm = rand() % 8;
        nred = tmpred + k1[sm];
        nstup = tmpstup + k2[sm];
        if (Moze(nred, nstup))
            Pomak(sm);

        //IspisPloce("POLJE", polje);
        /*IspisPloce("TAKEN", taken);
        printf("MOZE %d %d\n", bio[2][2], Moze(2, 2));
        system("pause");*/
    }
}

int main()
{
    int i, j, sm, da=0;
    str pocetak;
    map <int, int> :: iterator it;

    scanf("%d%d", &brred, &brstup);

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++) {
            scanf("%d", &polje[i][j]);
            M[polje[i][j]]++;
        }

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++) {
            scanf("%d", &kraj[i][j]);
            M[kraj[i][j]]--;
        }

    for (it=M.begin(); it!=M.end(); it++)
        if (it->second) {
            printf("-1\n");
            return 0;
        }

    if (brred > 1 && brstup > 1) {
        pocetak = Nadi(kraj[brred][brstup]);
        tmpred = pocetak.red;
        tmpstup = pocetak.stup;

        R.push_back(pocetak);

        for (i=1; i<=brred-2; i++)
            for (j=1; j<=brstup; j++) {
                Bfs(Nadi(kraj[i][j]), str(i, j));
                taken[i][j] = 1;
                /*if (Done()) {
                    IspisPot();
                    return 0;
                }*/
                //IspisPloce("POLJE", polje);
                //IspisPloce("TAKEN", taken);
            }

        /*printf("DA\n");
        IspisPloce("POLJE", polje);*/

        for (j=1; j<=brstup-2; j++)
            for (i=brred-1; i<=brred; i++) {
                //printf("KKK %d %d %d %d\n", Nadi(kraj[i][j]).red, Nadi(kraj[i][j]).stup, i, j);
                Bfs(Nadi(kraj[i][j]), str(i, j));
                taken[i][j] = 1;
                /*if (Done()) {
                    IspisPot();
                    return 0;
                }*/
                //IspisPloce("POLJE", polje);
                //IspisPloce("TAKEN", taken);
            }

        //printf("DA\n");

        RijesiKraj();
        da = 1;
        IspisPot();
    }
    else if (brred == 1) {
        memcpy(polje2, polje, sizeof polje);
        tmpred = 1;
        for (i=1; i<=brstup; i++) {
            for (j=1; j<=brstup; j++) {
                memcpy(polje, polje2, sizeof polje);
                R.clear();
                tmpstup = i;
                if (j > i)
                    sm = 2;
                else
                    sm = 6;

                R.push_back(str(1, i));
                for (; tmpstup != j; Pomak(sm));

                if (Done()) {
                    da = 1;
                    IspisPot();
                    break;
                }
            }
            if (da)
                break;
        }
    }
    else {
        memcpy(polje2, polje, sizeof polje);
        tmpstup = 1;
        for (i=1; i<=brred; i++) {
            for (j=1; j<=brred; j++) {
                memcpy(polje, polje2, sizeof polje);
                R.clear();
                tmpred = i;
                if (j > i)
                    sm = 4;
                else
                    sm = 0;

                R.push_back(str(i, 1));
                for (; tmpred != j; Pomak(sm));

                if (Done()) {
                    da = 1;
                    IspisPot();
                    break;
                }
            }
            if (da)
                break;
        }
    }

    if (!da)
        printf("-1\n");

    return 0;
}


#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <map>

using namespace std;

const int MAX = 1<<5;

struct str {
    int red, stup;
    str (int red, int stup) : red(red), stup(stup) {}
    str () {}
};

bool operator == (str a, str b) {
    return a.red == b.red && a.stup == b.stup;
}

int brred, brstup, polje[MAX][MAX], kraj[MAX][MAX], k1[8] = {-1, -1, 0, 1, 1, 1, 0, -1}, k2[8] = {0, 1, 1, 1, 0, -1, -1, -1}, tmpred, tmpstup;
int taken[MAX][MAX], bio[MAX][MAX], odakle1[MAX][MAX], odakle2[MAX][MAX], polje2[MAX][MAX];
queue <str> Q;
vector <str> R;
map <int, int> M;

void Pomak(int smjer)
{
    int nred, nstup;

    nred = tmpred + k1[smjer];
    nstup = tmpstup + k2[smjer];

    swap(polje[tmpred][tmpstup], polje[nred][nstup]);
    R.push_back(str(nred, nstup));
    tmpred = nred;
    tmpstup = nstup;
}

str Nadi(int val)
{
    int i, j;

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++)
            if (!taken[i][j] && polje[i][j] == val)
                return str(i, j);

    return str(-1, -1);
}

int Moze(int red, int stup)
{
    if (red < 1 || stup < 1 || red > brred || stup > brstup || taken[red][stup] || bio[red][stup])
        return 0;
    return 1;
}

void BfsPom(str to)
{
    int i, nred, nstup, da=0;
    str from, tmp;

    from = str(tmpred, tmpstup);

    for (; !Q.empty(); Q.pop());
    memset(bio, 0, sizeof bio);

    Q.push(to);
    bio[to.red][to.stup] = 1;

    for (; !Q.empty(); ) {
        tmp = Q.front();
        Q.pop();

        if (tmp == from) {
            da = 1;
            break;
        }

        for (i=0; i<8; i++) {
            nred = tmp.red + k1[i];
            nstup = tmp.stup + k2[i];
            if (Moze(nred, nstup)) {
                Q.push(str(nred, nstup));
                bio[nred][nstup] = 1;
                odakle1[nred][nstup] = (i+4) % 8;
            }
        }
    }

    for (; tmpred != to.red || tmpstup != to.stup;)
        Pomak(odakle1[tmpred][tmpstup]);

    if (!da)
        printf("NIJE NASO BFSPOM\n");
}

void Bfs(str from, str to)
{
    int i, nred, nstup, da=0;
    str tmp, slj;

    for (; !Q.empty(); Q.pop());
    memset(bio, 0, sizeof bio);

    Q.push(to);
    bio[to.red][to.stup] = 1;

    for (; !Q.empty(); ) {
        tmp = Q.front();
        Q.pop();

        if (tmp == from) {
            da = 1;
            break;
        }

        for (i=0; i<8; i++) {
            nred = tmp.red + k1[i];
            nstup = tmp.stup + k2[i];
            if (Moze(nred, nstup)) {
                Q.push(str(nred, nstup));
                bio[nred][nstup] = 1;
                odakle2[nred][nstup] = (i+4) % 8;
            }
        }
    }

    for (tmp=from; !(tmp == to);) {
        taken[tmp.red][tmp.stup] = 1;
        slj = str(tmp.red + k1[odakle2[tmp.red][tmp.stup]], tmp.stup + k2[odakle2[tmp.red][tmp.stup]]);
        BfsPom(slj);
        Pomak((4 + odakle2[tmp.red][tmp.stup]) % 8);
        taken[tmp.red][tmp.stup] = 0;
        tmp = slj;
    }

    if (!da)
        printf("NIJE NASO BFS\n");
}

void IspisPot()
{
    int i;

    printf("%u\n", R.size() - 1);
    for (i=0; (unsigned) i<R.size(); i++)
        printf("%d %d\n", R[i].red, R[i].stup);
}

void IspisPloce(char s[10], int p[MAX][MAX])
{
    int i, j;

    printf("%s\n", s);
    for (i=1; i<=brred; i++) {
        for (j=1; j<=brstup; j++)
            printf("%d ", p[i][j]);
        printf("\n");
    }
    printf("\n");
}

int Done()
{
    int i, j;

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++)
            if (polje[i][j] != kraj[i][j])
                return 0;
    return 1;
}
void RijesiKraj()
{
    int sm, nred, nstup, i, j, ne;

    memset(bio, 0, sizeof bio);

    for (;;) {
        ne = 0;
        for (i=brred-1; i<=brred; i++)
            for (j=brstup-1; j<=brstup; j++)
                if (polje[i][j] != kraj[i][j])
                    ne = 1;
        if (!ne)
            return;
        sm = rand() % 8;
        nred = tmpred + k1[sm];
        nstup = tmpstup + k2[sm];
        if (Moze(nred, nstup))
            Pomak(sm);

        //IspisPloce("POLJE", polje);
        /*IspisPloce("TAKEN", taken);
        printf("MOZE %d %d\n", bio[2][2], Moze(2, 2));
        system("pause");*/
    }
}

int main()
{
    int i, j, sm, da=0;
    str pocetak;
    map <int, int> :: iterator it;

    scanf("%d%d", &brred, &brstup);

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++) {
            scanf("%d", &polje[i][j]);
            M[polje[i][j]]++;
        }

    for (i=1; i<=brred; i++)
        for (j=1; j<=brstup; j++) {
            scanf("%d", &kraj[i][j]);
            M[kraj[i][j]]--;
        }

    for (it=M.begin(); it!=M.end(); it++)
        if (it->second) {
            printf("-1\n");
            return 0;
        }

    if (brred > 1 && brstup > 1) {
        pocetak = Nadi(kraj[brred][brstup]);
        tmpred = pocetak.red;
        tmpstup = pocetak.stup;

        R.push_back(pocetak);

        for (i=1; i<=brred-2; i++)
            for (j=1; j<=brstup; j++) {
                Bfs(Nadi(kraj[i][j]), str(i, j));
                taken[i][j] = 1;
                if (Done()) {
                    IspisPot();
                    return 0;
                }
                //IspisPloce("POLJE", polje);
                //IspisPloce("TAKEN", taken);
            }

        /*printf("DA\n");
        IspisPloce("POLJE", polje);*/

        for (j=1; j<=brstup-2; j++)
            for (i=brred-1; i<=brred; i++) {
                //printf("KKK %d %d %d %d\n", Nadi(kraj[i][j]).red, Nadi(kraj[i][j]).stup, i, j);
                Bfs(Nadi(kraj[i][j]), str(i, j));
                taken[i][j] = 1;
                if (Done()) {
                    IspisPot();
                    return 0;
                }
                //IspisPloce("POLJE", polje);
                //IspisPloce("TAKEN", taken);
            }

        printf("DA\n");

        RijesiKraj();
        da = 1;
        IspisPot();
    }
    else if (brred == 1) {
        memcpy(polje2, polje, sizeof polje);
        tmpred = 1;
        for (i=1; i<=brstup; i++) {
            for (j=1; j<=brstup; j++) {
                memcpy(polje, polje2, sizeof polje);
                R.clear();
                tmpstup = i;
                if (j > i)
                    sm = 2;
                else
                    sm = 6;

                R.push_back(str(1, i));
                for (; tmpstup != j; Pomak(sm));

                if (Done()) {
                    da = 1;
                    IspisPot();
                    break;
                }
            }
            if (da)
                break;
        }
    }
    else {
        memcpy(polje2, polje, sizeof polje);
        tmpstup = 1;
        for (i=1; i<=brred; i++) {
            for (j=1; j<=brred; j++) {
                memcpy(polje, polje2, sizeof polje);
                R.clear();
                tmpred = i;
                if (j > i)
                    sm = 4;
                else
                    sm = 0;

                R.push_back(str(i, 1));
                for (; tmpred != j; Pomak(sm));

                if (Done()) {
                    da = 1;
                    IspisPot();
                    break;
                }
            }
            if (da)
                break;
        }
    }

    if (!da)
        printf("-1\n");

    return 0;
}


#define _CRT_SECURE_NO_DEPRECATE
#define _USE_MATH_DEFINES
#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <climits>
#include <ctime>
#include <numeric>
#include <vector>
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstring>
#include <iomanip>
#include <complex>
#include <deque>
#include <functional>
#include <list>
#include <map>
#include <string>
#include <sstream>
#include <set>
#include <stack>
#include <queue>
using namespace std;
typedef long long lng;
typedef unsigned long long ulng;
typedef unsigned int uint;
typedef unsigned char uchar;
typedef double ld;
typedef pair<int, int> PII;
//typedef pair<short, short> PSS;
typedef pair<string, string> PSS;
typedef pair<PII, int> PIII;
typedef pair<lng, lng> PLL;
typedef pair<ulng, ulng> PUU;
typedef pair<lng, int> PLI;
typedef pair<int, lng> PIL;
typedef pair<ld, ld> PDD;
template<class T> inline T sqr(T x) { return x * x; }
template<class T> inline string tostr(const T & x) { stringstream ss; ss << x; return ss.str(); }
inline lng parse(const string & s) { stringstream ss(s); lng x; ss >> x; return x; }
#define left asdleft
#define right asdright
#define link asdlink
#define unlink asdunlink
#define next asdnext
#define prev asdprev
#define y0 asdy0
#define y1 asdy1
#define mp make_pair
#define pb push_back
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(), (x).end()
#define clr(ar,val) memset(ar, val, sizeof(ar))
#define istr stringstream
#define forn(i,n) for(int i=0;i<(n);++i)
#define forv(i,v) forn(i,sz(v))
#define X first
#define Y second
#define hash asdhash
#define move asdmove
const ld EPS = 1e-9;
const int INF = 1000*1000*1000;
const char CINF = 102;
const lng LINF = INF * 1ll * INF;
const ld DINF = 1e200;
const ld PI = 3.1415926535897932384626433832795l;
int gcd(int a,int b){return a?gcd(b%a,a):b;}
lng gcd(lng a,lng b){return a?gcd(b%a,a):b;}
lng powmod(lng a,lng p,lng m){lng r=1;while(p){if(p&1)r=r*a%m;p>>=1;a=a*a%m;}return r;}
#define FAIL { cerr<<"assertion failed on line "<<__LINE__<<endl; exit(123);}

int n,m;
vector<vector<int> > A,G;
vector<PII> ans;
int a,b;

void nope(){
	cout<<-1;
	exit(0);
}

void go(int aa,int bb){
	if(mp(aa,bb)==mp(a,b) || abs(a-aa)>1 || abs(b-bb)>1 || aa<0 || bb<0 || aa>=n || bb>=m)
		FAIL;
	swap(A[aa][bb],A[a][b]);
	a=aa;
	b=bb;
	ans.pb(mp(a,b));
}

void trans(){
	swap(n,m);
	vector<vector<int> > AA(n,vector<int>(m)),GG;
	GG=AA;
	forn(i,n){
		forn(j,m){
			AA[i][j]=A[j][i];
			GG[i][j]=G[j][i];
		}
	}
	forv(i,ans){
		swap(ans[i].X,ans[i].Y);
	}
	A=AA;
	G=GG;
}

void solve(){
	if(n==1 || m==1){
		bool tra=false;
		if(n>1){
			trans();
			tra=true;
		}

		bool f=false;
		forn(x,m){
			if(f)
				break;
			forn(y,m){
				if(f)
					break;
				if(x==y)
					continue;
				vector<int> T=A[0];
				if(y>x)
					rotate(T.begin()+x,T.begin()+x+1,T.begin()+y+1);
				else
					rotate(T.begin()+y,T.begin()+x,T.begin()+x+1);
				if(T==G[0]){
					f=true;
					a=0;
					b=x;
					ans.pb(mp(a,b));
					while(b>y)
						go(a,b-1);
					while(b<y)
						go(a,b+1);
				}
			}
		}

		if(!f)nope();

		if(tra)
			trans();
	}else{
		a=-1;
		for(int i=0;i<n&&a==-1;++i){
			for(int j=0;j<m&&a==-1;++j){
				if(A[i][j]==G[n-1][m-1])
					a=i,b=j;
			}
		}
		if(a==-1)
			FAIL;
		ans.pb(mp(a,b));

		for(int r=0;r<n-2;++r){
			for(int c=0;c<m;++c){
				while(b<c)
					go(a,b+1);
				while(b>c)
					go(a,b-1);
				while(a>r)
					go(a-1,b);
				if(a<r)
					FAIL;

				int aa=-1,bb=-1;
				for(int i=r;i<n && aa==-1;++i){
					for(int j=(i==r?c+1:0);j<m && aa==-1;++j){
						if(G[r][c]==A[i][j])
							aa=i,bb=j;
					}
				}
				if(aa==-1)
					FAIL;

				vector<PII> tr;
				if(bb>=c && c+1<m){
					go(a,b+1);
					if(aa==r)
						++aa;
					if(bb==c)
						++bb;
					for(int j=c+2;j<=bb;++j)
						tr.pb(mp(r,j));
					for(int i=r+1;i<=aa;++i)
						tr.pb(mp(i,bb));
					for(int j=bb-1;j>=c;--j)
						tr.pb(mp(aa,j));
					for(int i=aa-1;i>=r;--i)
						tr.pb(mp(i,c));
					tr.pb(mp(r,c+1));
				}else{
					go(a+1,b-1);
					if(aa==r+1)
						++aa;
					if(bb==c)
						--bb;
					for(int j=c-2;j>=bb;--j)
						tr.pb(mp(r+1,j));
					for(int i=r+2;i<=aa;++i)
						tr.pb(mp(i,bb));
					for(int j=bb+1;j<=c;++j)
						tr.pb(mp(aa,j));
					for(int i=aa-1;i>=r;--i)
						tr.pb(mp(i,c));
					tr.pb(mp(r+1,c-1));
				}

				int it=0;
				while(A[r][c]!=G[r][c]){
					if(it++>200)
						FAIL;
					forv(i,tr){
						go(tr[i].X,tr[i].Y);
					}
				}
			}
		}

		for(int c=0;c<m-1;++c){
			for(int r=n-2;r<n;++r){
				while(a<r)
					go(a+1,b);
				while(a>r)
					go(a-1,b);
				while(b>c)
					go(a,b-1);
				if(b<c)
					FAIL;

				go(n-2,c+1);

				vector<PII> tr;
				for(int j=c+2;j<m;++j)
					tr.pb(mp(n-2,j));
				tr.pb(mp(n-1,m-1));
				for(int j=m-2;j>=c;--j)
					tr.pb(mp(n-1,j));
				if(r==n-2)
					tr.pb(mp(n-2,c));
				tr.pb(mp(n-2,c+1));

				int it=0;
				while(A[r][c]!=G[r][c]){
					if(mp(a,b)!=mp(n-2,c+1))
						FAIL;
					if(it++>200)
						FAIL;
					forv(i,tr){
						go(tr[i].X,tr[i].Y);
					}
				}
			}
		}

		if(a!=n-1)
			go(n-1,m-1);
	}

	forn(i,n){
		forn(j,m){
			if(A[i][j]!=G[i][j])
				FAIL;
		}
	}
}

void stress(){
	for(n=2;n<=10;++n){
		for(m=2;m<=10;++m){
			cerr<<n<<' '<<m<<endl;
			forn(it,1000){
				ans.clear();
				A.clear();
				A.resize(n,vector<int>(m));
				G=A;
				vector<int> P1(n*m),P2(n*m);
				forn(i,n*m){
					P1[i]=P2[i]=i;
				}
				random_shuffle(all(P1));
				random_shuffle(all(P2));
				forn(i,n){
					forn(j,m){
						A[i][j]=P1[i*m+j];
						G[i][j]=P2[i*m+j];
					}
				}

				solve();
			}
		}
	}
}

int main(){
#ifdef __ASD__
	freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout);
#endif

	ios_base::sync_with_stdio(false);cin.tie(0);

	//stress();return 0;

	cin>>n>>m;
	A.resize(n,vector<int>(m));
	G=A;
	multiset<int> As,Gs;
	forn(i,n){
		forn(j,m){
			cin>>A[i][j];
			As.insert(A[i][j]);
		}
	}
	forn(i,n){
		forn(j,m){
			cin>>G[i][j];
			Gs.insert(G[i][j]);
		}
	}

	if(As!=Gs)
		nope();

	solve();

	cout<<sz(ans)-1<<endl;
	forv(i,ans){
		cout<<ans[i].X+1<<' '<<ans[i].Y+1<<'\n';
	}

	return 0;
}


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <set>
#include <map>
#include <list>
#include <stack>
#include <deque>
#include <queue>
#include <algorithm>
#include <cassert>
#include <cmath>
#include <ctime>
#include <sstream>
#include <unordered_set>
#include <unordered_map>
#include <functional>
#include <bitset>
#include <valarray>
#include <utility>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace __gnu_pbds;
using namespace std;

#ifdef LOCAL_RUN
#define debug(x) cerr << #x << ": "  << (x) << "\n";
#else
#define debug(x) ;
#endif

#define all(v) (v).begin(), (v).end()
#define MP make_pair

template<class T>
class IsIterable__ {static void f(...); template<class U> static typename U::const_iterator f(const U&);
public:const static bool value = !std::is_same<void, decltype(f(std::declval<T>()))>::value;};

template <class F, class S> ostream& operator << (ostream& o, const pair<F,S>& p) {
return o << "(" << p.first << ", " << p.second << ")";}

template<class C>void O__(ostream& o, const C& c) {
bool f = 1; for(const auto& x: c) {if (!f) o << ", "; if (IsIterable__<decltype(x)>::value) o << "\n"; f = 0; o << x;}}

template <class T>
ostream& operator << (ostream& o, const vector<T>& v) {o << "[";O__(o, v);o << "]";return o;}

template <class T, class V>
ostream& operator << (ostream& o, const map<T, V>& v) {o << "{";O__(o, v);o << "}"; return o;}

template <class T>
ostream& operator << (ostream& o, const set<T>& v) {o << "{";O__(o, v);o << "}";return o;}

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;
typedef vector<int> vi;
typedef vector<vi> vii;
typedef vector<vii> viii;

const double PI = 3.1415926535897932384626433832795;
const double EPS = 1e-9;
const int INF = std::numeric_limits<int>::max();
const long long LLINF = std::numeric_limits<ll>::max();

// supports find_by_order(int) and order_of_key(Key)
template<class Key, class Value>
using MapWithOrderStatistics = tree<Key, Value,
      std::less<Key>, rb_tree_tag /*splay_tree_tag*/,
      tree_order_statistics_node_update>;

ll sqr(int x) {
    return 1LL * x * x;
}

struct State {
    //vector<vi> plan;
    vector<vi> plan;
    int i, j;
    bool operator<(const State& s) const {
        return t() < s.t();
    }
    tuple<vector<vi>, int, int> t() const {
        return make_tuple(plan, i, j);
    }
};

int XS[900];
int YS[900];

int curCX[900];
int curCY[900];

int STEP;
State global;
ll globalScore;

ll score(const State& x, int step);

int CCCC;
const int MAXCCCC = 1000*1000*10;

vector<pii> path;
vector<pii> tmp;

void dfs(State& s, ll curScore, int d) {
    /*ll SC = score(s, STEP);
    if (SC > score(global, STEP) + 2000) {
        if (rand() & 1)
            return;
    }*/
    ++CCCC;
    if (CCCC > MAXCCCC)
        return;
    //if (curScore > globalScore ) {
        //if (CCCC % 3 == 0)
        //    return;
    //}
    //debug(STEP);
    //debug(s.plan);
    //debug(curScore);
    //debug(score(s,STEP));
    //assert(curScore == score(s, STEP));
    if (curScore < globalScore) {
        path = tmp;
        globalScore = curScore;
        global = s;
    }
    if (d == 0)
        return;
    for (int dx = -1; dx <= +1; ++dx)
        for (int dy = -1; dy <= +1; ++dy) {
            if (dx == 0 && dy == 0)
                continue;
            int ox = s.i;
            int oy = s.j;
            int x = s.i + dx;
            int y = s.j + dy;
            if (x < 0 || y < 0 || x >= s.plan.size() || y >= s.plan[0].size()) {
                continue;
            }

            //debug(STEP);
            //debug(s.plan);
            //debug(curScore);
            //debug(score(s,STEP));
            //assert(curScore == score(s, STEP));

            ll oldCurScore = curScore;
            int first = s.plan[ox][oy];
            int second = s.plan[x][y];
            //debug(first);
            //assert(s.plan[curCX[first]][curCY[first]] == first);
            //assert(s.plan[curCX[second]][curCY[second]] == second);

            //debug(curScore);
            if (first < STEP) {
                curScore -= 1000 * (sqr(XS[first] - curCX[first]) + sqr(YS[first] - curCY[first]) );
            }
            if (first == STEP) {
                curScore -= 10000 * (sqr(XS[first] - curCX[first]) + sqr(YS[first] - curCY[first]) );
            }
            //std::cerr << "Remove " << first << " " << curScore << "\n";
            //debug(curScore);
            if (second < STEP) {
                curScore -= 1000 * (sqr(XS[second] - curCX[second]) + sqr(YS[second] - curCY[second]) );
            }
            if (second == STEP) {
                curScore -= 10000 * (sqr(XS[second] - curCX[second]) + sqr(YS[second] - curCY[second]) );
            }
            //std::cerr << "Remove " << second << " " << curScore << "\n";

            if (STEP < s.plan.size() * s.plan[0].size()) {
                /*debug(s.plan);
                debug(STEP);
                debug(curCX[STEP]);
                debug(curCY[STEP]);
                debug(s.i);
                debug(s.j);*/
                curScore -= sqr(curCX[STEP] - s.i);
                curScore -= sqr(curCY[STEP] - s.j);
            }
            //std::cerr << "Remove addition" << " " << curScore << "\n";

            //debug(curScore);
            //assert(curScore % 1000 == 0);
            tmp.push_back(pii(x,y));

            swap(s.plan[ox][oy], s.plan[x][y]);
            curCX[first] = x;
            curCY[first] = y;
            curCX[second] = ox;
            curCY[second] = oy;
            //assert(s.plan[curCX[first]][curCY[first]] == first);
            //assert(s.plan[curCX[second]][curCY[second]] == second);

            if (first < STEP) {
                curScore += 1000 * (sqr(XS[first] - curCX[first]) + sqr(YS[first] - curCY[first]));
            }
            if (first == STEP) {
                curScore += 10000 * (sqr(XS[first] - curCX[first]) + sqr(YS[first] - curCY[first]));
            }
            //std::cerr << "Add" << first << " " << curScore << "\n";
            if (second < STEP) {
                curScore += 1000 * (sqr(XS[second] - curCX[second]) + sqr(YS[second] - curCY[second]));
            }
            if (second == STEP) {
                curScore += 10000 * (sqr(XS[second] - curCX[second]) + sqr(YS[second] - curCY[second])) ;
            }
            //std::cerr << "Add" << second << " " << curScore << "\n";

            if (STEP < s.plan.size() * s.plan[0].size()) {
                curScore += sqr(curCX[STEP] - x);
                curScore += sqr(curCY[STEP] - y);
            }
            //std::cerr << "Add" << " addition"<< " " << curScore << "\n";

            s.i = x;
            s.j = y;
            //assert(s.plan[curCX[first]][curCY[first]] == first);
            //assert(s.plan[curCX[second]][curCY[second]] == second);
            dfs(s, curScore, d - 1);
            tmp.pop_back();
            swap(s.plan[ox][oy], s.plan[x][y]);
            curCX[first] = ox;
            curCY[first] = oy;
            curCX[second] = x;
            curCY[second] = y;
            s.i = ox;
            s.j = oy;
            //assert(s.plan[curCX[first]][curCY[first]] == first);
            //assert(s.plan[curCX[second]][curCY[second]] == second);

            curScore = oldCurScore;
        }
}

ll score(const State& x, int step) {
    vector<pii> a(x.plan.size() * x.plan[0].size());
    for (int i = 0; i < x.plan.size(); ++i) {
        for (int j = 0; j < x.plan[0].size(); ++j) {
            a[x.plan[i][j]] = pii(i,j);
        }
    }
//dd
    ll res = 0;
    for (int i = 0; i <= step && i < a.size();++i) {
        int X = XS[i];
        int Y = YS[i];
        ll cur = sqr(X - a[i].first) + sqr(Y - a[i].second) ;
        if (i < step) {
            res += cur;
        }
        if (i == step) {
            res += 10*cur;
        }
    }
    res *= 1000;
    if (step<a.size()){
        res += sqr(a[step].first - x.i);
        res += sqr(a[step].second - x.j);
    }
    //assert(res >= 0);
    return res;
}

bool go(State x, vector<pii>& res) {
    res.clear();
    res.push_back(pii(x.i, x.j));
    int step = 0;
    while (step != x.plan.size() * x.plan[0].size()) {
        //debug(x.plan);
        while (step < x.plan.size() * x.plan[0].size()) {
            int X = XS[step];
            int Y = YS[step];
            if (x.plan[X][Y] == step) {
                ++step;
            } else {
                break;
            }
        }
        if (step == x.plan.size() * x.plan[0].size())
            break;
        //debug(step);
        global = x;
        globalScore = score(global, step);
        STEP = step;
        int de = 2;
        while (!(x < global || global < x)) {
            dfs(x, globalScore, de);
            if (CCCC > MAXCCCC)
                return 0;
            //debug(de);
            de += 1;
        }
        for (int i = 0; i < path.size(); ++i)
            res.push_back(path[i]);
        x = global;
        for (int i = 0; i < x.plan.size(); ++i)
            for (int j = 0; j < x.plan[0].size(); ++j) {
                curCX[x.plan[i][j]] = i;
                curCY[x.plan[i][j]] = j;
            }
    }
    debug(x.plan);
    //cout << res.size()-1 << "\n";
    //for (int i = 0;i < res.size(); ++i)
    //    cout << 1+res[i].first << " " << 1+res[i].second << "\n";
    return true;
}

int main() {
    CCCC=0;
    /*int n = 3;
    int m = 3;
    vector<vi> plan(m, vi(n, '?'));
    int id = 0;
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            plan[i][j] = char('a' + id);
            ++id;
        }
    }
    State st;
    st.plan = plan;
    st.i = m/2;
    st.j = n/2;
    dfs(st);
    debug(used.size());*/

    int n, m;
    cin >> n >> m;
    vii origin(n, vi(m, -1));
    vii target(n, vi(m, -1));
    for (int i = 0 ;i < n; ++i) {
        for (int j = 0; j < m; ++j)
            cin >> origin[i][j];
    }
    for (int i = 0 ;i < n; ++i) {
        for (int j = 0; j < m; ++j)
            cin >> target[i][j];
    }
    vector<vi> plan(n, vi(m, 0));
    vii t2(target);
    vii o3(origin);

    int I = 0;
    for (int x = 0; x + 2 * (m>1) < n; ++x) {
        for (int y = 0; y < m; ++y) {
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < m; ++j) {
                    if (origin[i][j] == target[x][y]) {
                        target[x][y] = -2;
                        origin[i][j] = -1;
                        plan[i][j] = I;
                        XS[I] = x;
                        YS[I] = y;
                        curCX[I] = i;
                        curCY[I] = j;

                        ++I;
                    }
                }
            }
        }
    }

    if (m>1){
    for (int y = 0; y < m; ++y) {
        for (int x = max(n-2, 0); x < n; ++x) {
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < m; ++j) {
                    if (origin[i][j] == target[x][y]) {
                        target[x][y] = -2;
                        origin[i][j] = -1;
                        plan[i][j] = I;
                        XS[I] = x;
                        YS[I] = y;

                        curCX[I] = i;
                        curCY[I] = j;
                        ++I;
                    }
                }
            }
        }
    }
    }

    if (n == 1) {
        for (int i = 0; i < m; ++i)
            for (int j = 0; j < m; ++j) {
                vii o2(o3);
                int x = i;
                vector<pii> res;
                res.push_back(pii(0, x));
                while (x != j) {
                    int nx = x+(j-x)/abs(j-x);
                    swap(o2[0][x], o2[0][nx]);
                    res.push_back(pii(0, nx));
                    x = nx;
                }
                if (o2 == t2) {
                    cout << res.size()-1 << "\n";
                    for (int i = 0;i < res.size(); ++i)
                        cout << 1+res[i].first << " " << 1+res[i].second << "\n";
                    return 0;
                }
            }
        cout << "-1\n";
        return 0;
    }
    if (m == 1) {
        for (int i = 0; i < n; ++i)
            for (int j = 0; j < n; ++j) {
                vii o2(o3);
                int x = i;
                vector<pii> res;
                res.push_back(pii(x,0));
                while (x != j) {
                    int nx = x+(j-x)/abs(j-x);
                    swap(o2[x][0], o2[nx][0]);
                    res.push_back(pii(nx,0));
                    x = nx;
                }
                if (o2 == t2) {
                    cout << res.size()-1 << "\n";
                    for (int i = 0;i < res.size(); ++i)
                        cout << 1+res[i].first << " " << 1+res[i].second << "\n";
                    return 0;
                }
            }
        cout << "-1\n";
        return 0;
    }

    debug(plan)
    State st;
    st.plan = plan;
    st.i = curCX[plan.size() * plan[0].size() - 1];
    st.j = curCY[plan.size() * plan[0].size() - 1];
    vector<pii> res;
    if (go(st, res)) {
        cout << res.size()-1 << "\n";
        for (int i = 0;i < res.size(); ++i)
            cout << 1+res[i].first << " " << 1+res[i].second << "\n";
    } else {
        cout << "-1\n";
    }

    return 0;
}


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <set>
#include <map>
#include <list>
#include <stack>
#include <deque>
#include <queue>
#include <algorithm>
#include <cassert>
#include <cmath>
#include <ctime>
#include <sstream>
#include <unordered_set>
#include <unordered_map>
#include <functional>
#include <bitset>
#include <valarray>
#include <utility>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace __gnu_pbds;
using namespace std;

#ifdef LOCAL_RUN
#define debug(x) cerr << #x << ": "  << (x) << "\n";
#else
#define debug(x) ;
#endif

#define all(v) (v).begin(), (v).end()
#define MP make_pair

template<class T>
class IsIterable__ {static void f(...); template<class U> static typename U::const_iterator f(const U&);
public:const static bool value = !std::is_same<void, decltype(f(std::declval<T>()))>::value;};

template <class F, class S> ostream& operator << (ostream& o, const pair<F,S>& p) {
return o << "(" << p.first << ", " << p.second << ")";}

template<class C>void O__(ostream& o, const C& c) {
bool f = 1; for(const auto& x: c) {if (!f) o << ", "; if (IsIterable__<decltype(x)>::value) o << "\n"; f = 0; o << x;}}

template <class T>
ostream& operator << (ostream& o, const vector<T>& v) {o << "[";O__(o, v);o << "]";return o;}

template <class T, class V>
ostream& operator << (ostream& o, const map<T, V>& v) {o << "{";O__(o, v);o << "}"; return o;}

template <class T>
ostream& operator << (ostream& o, const set<T>& v) {o << "{";O__(o, v);o << "}";return o;}

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;
typedef vector<int> vi;
typedef vector<vi> vii;
typedef vector<vii> viii;

const double PI = 3.1415926535897932384626433832795;
const double EPS = 1e-9;
const int INF = std::numeric_limits<int>::max();
const long long LLINF = std::numeric_limits<ll>::max();

// supports find_by_order(int) and order_of_key(Key)
template<class Key, class Value>
using MapWithOrderStatistics = tree<Key, Value,
      std::less<Key>, rb_tree_tag /*splay_tree_tag*/,
      tree_order_statistics_node_update>;

ll sqr(int x) {
    return 1LL * x * x;
}

struct State {
    //vector<vi> plan;
    vector<vi> plan;
    int i, j;
    bool operator<(const State& s) const {
        return t() < s.t();
    }
    tuple<vector<vi>, int, int> t() const {
        return make_tuple(plan, i, j);
    }
};

int XS[900];
int YS[900];

int curCX[900];
int curCY[900];

int STEP;
State global;
ll globalScore;

ll score(const State& x, int step);

int CCCC;

vector<pii> path;
vector<pii> tmp;

void dfs(State& s, ll curScore, int d) {
    /*ll SC = score(s, STEP);
    if (SC > score(global, STEP) + 2000) {
        if (rand() & 1)
            return;
    }*/
    ++CCCC;
    //if (curScore > globalScore ) {
        //if (CCCC % 3 == 0)
        //    return;
    //}
    //debug(STEP);
    //debug(s.plan);
    //debug(curScore);
    //debug(score(s,STEP));
    //assert(curScore == score(s, STEP));
    if (curScore < globalScore) {
        path = tmp;
        globalScore = curScore;
        global = s;
    }
    if (d == 0)
        return;
    for (int dx = -1; dx <= +1; ++dx)
        for (int dy = -1; dy <= +1; ++dy) {
            if (dx == 0 && dy == 0)
                continue;
            int ox = s.i;
            int oy = s.j;
            int x = s.i + dx;
            int y = s.j + dy;
            if (x < 0 || y < 0 || x >= s.plan.size() || y >= s.plan[0].size()) {
                continue;
            }

            //debug(STEP);
            //debug(s.plan);
            //debug(curScore);
            //debug(score(s,STEP));
            //assert(curScore == score(s, STEP));

            ll oldCurScore = curScore;
            int first = s.plan[ox][oy];
            int second = s.plan[x][y];
            //debug(first);
            //assert(s.plan[curCX[first]][curCY[first]] == first);
            //assert(s.plan[curCX[second]][curCY[second]] == second);

            //debug(curScore);
            if (first < STEP) {
                curScore -= 1000 * (sqr(XS[first] - curCX[first]) + sqr(YS[first] - curCY[first]) );
            }
            if (first == STEP) {
                curScore -= 10000 * (sqr(XS[first] - curCX[first]) + sqr(YS[first] - curCY[first]) );
            }
            //std::cerr << "Remove " << first << " " << curScore << "\n";
            //debug(curScore);
            if (second < STEP) {
                curScore -= 1000 * (sqr(XS[second] - curCX[second]) + sqr(YS[second] - curCY[second]) );
            }
            if (second == STEP) {
                curScore -= 10000 * (sqr(XS[second] - curCX[second]) + sqr(YS[second] - curCY[second]) );
            }
            //std::cerr << "Remove " << second << " " << curScore << "\n";

            if (STEP < s.plan.size() * s.plan[0].size()) {
                /*debug(s.plan);
                debug(STEP);
                debug(curCX[STEP]);
                debug(curCY[STEP]);
                debug(s.i);
                debug(s.j);*/
                curScore -= sqr(curCX[STEP] - s.i);
                curScore -= sqr(curCY[STEP] - s.j);
            }
            //std::cerr << "Remove addition" << " " << curScore << "\n";

            //debug(curScore);
            //assert(curScore % 1000 == 0);
            tmp.push_back(pii(x,y));

            swap(s.plan[ox][oy], s.plan[x][y]);
            curCX[first] = x;
            curCY[first] = y;
            curCX[second] = ox;
            curCY[second] = oy;
            //assert(s.plan[curCX[first]][curCY[first]] == first);
            //assert(s.plan[curCX[second]][curCY[second]] == second);

            if (first < STEP) {
                curScore += 1000 * (sqr(XS[first] - curCX[first]) + sqr(YS[first] - curCY[first]));
            }
            if (first == STEP) {
                curScore += 10000 * (sqr(XS[first] - curCX[first]) + sqr(YS[first] - curCY[first]));
            }
            //std::cerr << "Add" << first << " " << curScore << "\n";
            if (second < STEP) {
                curScore += 1000 * (sqr(XS[second] - curCX[second]) + sqr(YS[second] - curCY[second]));
            }
            if (second == STEP) {
                curScore += 10000 * (sqr(XS[second] - curCX[second]) + sqr(YS[second] - curCY[second])) ;
            }
            //std::cerr << "Add" << second << " " << curScore << "\n";

            if (STEP < s.plan.size() * s.plan[0].size()) {
                curScore += sqr(curCX[STEP] - x);
                curScore += sqr(curCY[STEP] - y);
            }
            //std::cerr << "Add" << " addition"<< " " << curScore << "\n";

            s.i = x;
            s.j = y;
            //assert(s.plan[curCX[first]][curCY[first]] == first);
            //assert(s.plan[curCX[second]][curCY[second]] == second);
            dfs(s, curScore, d - 1);
            tmp.pop_back();
            swap(s.plan[ox][oy], s.plan[x][y]);
            curCX[first] = ox;
            curCY[first] = oy;
            curCX[second] = x;
            curCY[second] = y;
            s.i = ox;
            s.j = oy;
            //assert(s.plan[curCX[first]][curCY[first]] == first);
            //assert(s.plan[curCX[second]][curCY[second]] == second);

            curScore = oldCurScore;
        }
}

ll score(const State& x, int step) {
    vector<pii> a(x.plan.size() * x.plan[0].size());
    for (int i = 0; i < x.plan.size(); ++i) {
        for (int j = 0; j < x.plan[0].size(); ++j) {
            a[x.plan[i][j]] = pii(i,j);
        }
    }
//dd
    ll res = 0;
    for (int i = 0; i <= step && i < a.size();++i) {
        int X = XS[i];
        int Y = YS[i];
        ll cur = sqr(X - a[i].first) + sqr(Y - a[i].second) ;
        if (i < step) {
            res += cur;
        }
        if (i == step) {
            res += 10*cur;
        }
    }
    res *= 1000;
    if (step<a.size()){
        res += sqr(a[step].first - x.i);
        res += sqr(a[step].second - x.j);
    }
    //assert(res >= 0);
    return res;
}

bool go(State x, vector<pii>& res) {
    res.clear();
    res.push_back(pii(x.i, x.j));
    int step = 0;
    while (step != x.plan.size() * x.plan[0].size()) {
        //debug(x.plan);
        while (step < x.plan.size() * x.plan[0].size()) {
            int X = XS[step];
            int Y = YS[step];
            if (x.plan[X][Y] == step) {
                ++step;
            } else {
                break;
            }
        }
        if (step == x.plan.size() * x.plan[0].size())
            break;
        //debug(step);
        global = x;
        globalScore = score(global, step);
        STEP = step;
        int de = 2;
        while (!(x < global || global < x)) {
            dfs(x, globalScore, de);
            //debug(de);
            de += 1;
        }
        for (int i = 0; i < path.size(); ++i)
            res.push_back(path[i]);
        x = global;
        for (int i = 0; i < x.plan.size(); ++i)
            for (int j = 0; j < x.plan[0].size(); ++j) {
                curCX[x.plan[i][j]] = i;
                curCY[x.plan[i][j]] = j;
            }
    }
    debug(x.plan);
    //cout << res.size()-1 << "\n";
    //for (int i = 0;i < res.size(); ++i)
    //    cout << 1+res[i].first << " " << 1+res[i].second << "\n";
    return true;
}

int main() {
    CCCC=0;
    /*int n = 3;
    int m = 3;
    vector<vi> plan(m, vi(n, '?'));
    int id = 0;
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            plan[i][j] = char('a' + id);
            ++id;
        }
    }
    State st;
    st.plan = plan;
    st.i = m/2;
    st.j = n/2;
    dfs(st);
    debug(used.size());*/

    int n, m;
    cin >> n >> m;
    vii origin(n, vi(m, -1));
    vii target(n, vi(m, -1));
    for (int i = 0 ;i < n; ++i) {
        for (int j = 0; j < m; ++j)
            cin >> origin[i][j];
    }
    for (int i = 0 ;i < n; ++i) {
        for (int j = 0; j < m; ++j)
            cin >> target[i][j];
    }
    vector<vi> plan(n, vi(m, 0));
    vii t2(target);
    vii o3(origin);

    int I = 0;
    for (int x = 0; x + 2 * (m>1) < n; ++x) {
        for (int y = 0; y < m; ++y) {
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < m; ++j) {
                    if (origin[i][j] == target[x][y]) {
                        target[x][y] = -2;
                        origin[i][j] = -1;
                        plan[i][j] = I;
                        XS[I] = x;
                        YS[I] = y;
                        curCX[I] = i;
                        curCY[I] = j;

                        ++I;
                    }
                }
            }
        }
    }

    if (m>1){
    for (int y = 0; y < m; ++y) {
        for (int x = max(n-2, 0); x < n; ++x) {
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < m; ++j) {
                    if (origin[i][j] == target[x][y]) {
                        target[x][y] = -2;
                        origin[i][j] = -1;
                        plan[i][j] = I;
                        XS[I] = x;
                        YS[I] = y;

                        curCX[I] = i;
                        curCY[I] = j;
                        ++I;
                    }
                }
            }
        }
    }
    }

    if (n == 1) {
        for (int i = 0; i < m; ++i)
            for (int j = 0; j < m; ++j) {
                vii o2(o3);
                int x = i;
                vector<pii> res;
                res.push_back(pii(0, x));
                while (x != j) {
                    int nx = x+(j-x)/abs(j-x);
                    swap(o3[0][x], o3[0][nx]);
                    res.push_back(pii(0, nx));
                    x = nx;
                }
                if (o2 == t2) {
                    cout << res.size()-1 << "\n";
                    for (int i = 0;i < res.size(); ++i)
                        cout << 1+res[i].first << " " << 1+res[i].second << "\n";
                    return 0;
                }
            }
        cout << "-1\n";
        return 0;
    }
    if (m == 1) {
        for (int i = 0; i < n; ++i)
            for (int j = 0; j < n; ++j) {
                vii o2(o3);
                int x = i;
                vector<pii> res;
                res.push_back(pii(x,0));
                while (x != j) {
                    int nx = x+(j-x)/abs(j-x);
                    swap(o2[x][0], o2[nx][0]);
                    res.push_back(pii(nx,0));
                    x = nx;
                }
                if (o2 == t2) {
                    cout << res.size()-1 << "\n";
                    for (int i = 0;i < res.size(); ++i)
                        cout << 1+res[i].first << " " << 1+res[i].second << "\n";
                    return 0;
                }
            }
        cout << "-1\n";
        return 0;
    }

    debug(plan)
    State st;
    st.plan = plan;
    st.i = curCX[plan.size() * plan[0].size() - 1];
    st.j = curCY[plan.size() * plan[0].size() - 1];
    vector<pii> res;
    if (go(st, res)) {
        cout << res.size()-1 << "\n";
        for (int i = 0;i < res.size(); ++i)
            cout << 1+res[i].first << " " << 1+res[i].second << "\n";
    } else {
        cout << "-1\n";
    }

    return 0;
}