#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 (CCCC >= 1000*1000*10) {
        cout << "-1\n";
        exit(0);
    }
    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.size(); ++j) {
            a[x.plan[i][j]] = pii(i,j);
        }
    }
    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.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));

    int I = 0;
    for (int x = 0; x + 2 < 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;
                    }
                }
            }
        }
    }

    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;
                    }
                }
            }
        }
    }

    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];
    go(st);

    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 = 3;
        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<bits/stdc++.h>
#define REP(i,m) for(int i=0;i<(m);++i)
#define REPN(i,m,in) for(int i=(in);i<(m);++i)
#define ALL(t) (t).begin(),(t).end()
#define CLR(a) memset((a),0,sizeof(a))
#define pb push_back
#define mp make_pair
#define fr first
#define sc second

using namespace std;

#ifndef ONLINE_JUDGE
#define dump(x)  cerr << #x << " = " << (x) << endl
#define prl cerr<<"called:"<< __LINE__<<endl
template<class T> void debug(T a,T b){ for(;a!=b;++a) cerr<<*a<<' ';cerr<<endl;}
#else
#define dump(x) ;
#define prl ;
template<class T> void debug(T a,T b){ ;}
#endif

template<class T> void chmin(T& a,const T& b) { if(a>b) a=b; }
template<class T> void chmax(T& a,const T& b) { if(a<b) a=b; }
typedef long long int lint;
typedef pair<int,int> pi;

namespace std{
	template<class S,class T>
	ostream &operator <<(ostream& out,const pair<S,T>& a){
		out<<'('<<a.fr<<','<<a.sc<<')';
		return out;
	}
}

lint readL(){
	lint res;
#ifdef ONLINE_JUDGE
	scanf("%I64d",&res);
#else
	scanf("%lld",&res);
#endif
	return res;
}
void printL(lint res){
#ifdef ONLINE_JUDGE
	printf("%I64d",res);
#else
	printf("%lld",res);
#endif
}

//const int INF=5e8;

int h,w;
int buf[35][35];
int goal[35][35];
pi res[1000005];
int mark[35][35];
int cnt;
int sx,sy;

void up(){
	swap(buf[sy][sx],buf[sy-1][sx]);
	--sy;
	res[cnt++]=mp(sy,sx);
}
void down(){
	swap(buf[sy][sx],buf[sy+1][sx]);
	++sy;
	res[cnt++]=mp(sy,sx);
}
void right(){

	swap(buf[sy][sx+1],buf[sy][sx]);
	++sx;
	res[cnt++]=mp(sy,sx);
}
void left(){
	swap(buf[sy][sx-1],buf[sy][sx]);
	--sx;
	res[cnt++]=mp(sy,sx);
}

int id[35][35],curid=1;
pi back[35][35];
void go(int y,int x){
	++curid;
	queue<pi>q;q.push(mp(sy,sx));
	while(!q.empty()){
		pi cur=q.front();q.pop();
		REPN(dx,2,-1) REPN(dy,2,-1) {
			if(dx==0 && dy==0) continue;
			int px=cur.sc+dx,py=cur.fr+dy;
			if(px<0 || py<0 || px>=w || py>=h || mark[py][px] || id[py][px]==curid) continue;
			q.push(mp(py,px));
			id[py][px]=curid;
			back[py][px]=mp(cur.fr,cur.sc);

			if(mp(py,px)==mp(y,x)){
				goto exi4;
			}
		}
	}
exi4:;
	 prl;
	 vector<pi> way;
	 pi cur=mp(y,x);
	 while(cur!=mp(sy,sx)){
		 way.pb(cur);
		 cur=back[cur.fr][cur.sc];
	 }
	 reverse(ALL(way));
	 REP(i,way.size()){
		 swap(buf[way[i].fr][way[i].sc],buf[sy][sx]);
		 sy=way[i].fr;sx=way[i].sc;
		 res[cnt++]=way[i];
	 }
	 sx=x;sy=y;
}

void moveR(int y,int x){
	mark[y][x]=1;
	go(y,x+1);
	left();
	mark[y][x]=0;
}
void moveL(int y,int x){
	mark[y][x]=1;
	go(y,x-1);
	right();
	mark[y][x]=0;
}
void moveD(int y,int x){
	mark[y][x]=1;
	go(y+1,x);
	up();
	mark[y][x]=0;
}

void moveU(int y,int x){
	mark[y][x]=1;
	go(y-1,x);
	down();
	mark[y][x]=0;
}

void end(){
	puts("-1");
	exit(0);
}
void print(){

	printf("%d\n",cnt-1);
	REP(i,cnt) printf("%d %d\n",res[i].fr+1,res[i].sc+1);
	exit(0);
}

int main(){
	cin>>h>>w;
	REP(i,h) REP(j,w) cin>>buf[i][j];
	REP(i,h) REP(j,w) cin>>goal[i][j];
	if(h<2 || w<2){
		int ar[35]={0},ar2[35]={0};
		int n;
		if(h==1){
			REP(i,w) ar[i]=buf[0][i],ar2[i]=goal[0][i];
			n=w;
		}else{
			REP(i,h) ar[i]=buf[i][0],ar2[i]=goal[i][0];
			n=h;
		}

		REP(i,n) if(ar[i]!=ar2[i]){
			REPN(j,n,i+1) if(ar2[i]==ar[j]){
				dump(i);dump(j);
				rotate(ar+i,ar+j,ar+j+1);

				int fail=0;
				REP(k,n) if(ar[k]!=ar2[k]) fail=1;

				if(!fail){
					for(int k=j;k>=i;--k) res[cnt++]=mp(k,0);
					goto exi3;
				}
				rotate(ar+i,ar+i+1,ar+j+1);
			}
			REPN(j,n,i+1) if(ar2[j]==ar[i]){
				rotate(ar+i,ar+i+1,ar+j+1);
				int fail=0;
				REP(k,n) if(ar[k]!=ar2[k]) fail=1;

				if(!fail){
					for(int k=i;k<=j;++k) res[cnt++]=mp(k,0);
					goto exi3;
				}
				rotate(ar+i,ar+j,ar+j+1);
			}
			break;
		}
		end();
exi3:;
	 	if(w==1) ;
		else REP(i,cnt) {
			swap(res[i].fr,res[i].sc);
		}

		print();

	}
	sx=sy=-1;
	REP(i,h) REP(j,w) if(buf[i][j]==goal[h-1][w-1]){
		sy=i;sx=j;
	}
	if(sx==-1) end();
	res[cnt++]=mp(sy,sx);

	REP(i,h-2) REP(j,w){
		pi pos;
		REP(k,h) REP(l,w) if(!mark[k][l] && mp(k,l)!=mp(sy,sx) && goal[i][j]==buf[k][l]){
			pos=mp(k,l);
			goto exi;
		}
		end();
exi:;

		while(pos!=mp(i,j)){
			if(pos.sc<j){
				moveR(pos.fr,pos.sc);++pos.sc;
			}
			else if(pos.sc>j){
				moveL(pos.fr,pos.sc);
				--pos.sc;
			}
			else if(pos.fr>i){
				moveU(pos.fr,pos.sc);
				--pos.fr;
			}
		}
		mark[i][j]=1;
	}

	REP(j,w-1) REPN(i,h,h-2){

		dump(i);dump(j);
		dump(mp(sy,sx));
		pi pos;
		REP(k,h) REP(l,w) if(!mark[k][l] && mp(k,l) != mp(sy,sx) && goal[i][j]==buf[k][l]){
			pos=mp(k,l);
			goto exi2;
		}
		end();
exi2:;
	 dump(pos);

	 	while(pos!=mp(i,j)){
			if(i<pos.fr){
				moveU(pos.fr,pos.sc);
				--pos.fr;
			}
			else if(i>pos.fr) {
				moveD(pos.fr,pos.sc);
				++pos.fr;
			}
			else{
				moveL(pos.fr,pos.sc);
				--pos.sc;
			}
		}
		mark[i][j]=1;
	}

	if(sy<h-1) down();

	if(buf[h-2][w-1]==goal[h-2][w-1]);
	else end();

	print();
	return 0;
}


#include<bits/stdc++.h>
#define REP(i,m) for(int i=0;i<(m);++i)
#define REPN(i,m,in) for(int i=(in);i<(m);++i)
#define ALL(t) (t).begin(),(t).end()
#define CLR(a) memset((a),0,sizeof(a))
#define pb push_back
#define mp make_pair
#define fr first
#define sc second

using namespace std;

#ifndef ONLINE_JUDGE
#define dump(x)  cerr << #x << " = " << (x) << endl
#define prl cerr<<"called:"<< __LINE__<<endl
template<class T> void debug(T a,T b){ for(;a!=b;++a) cerr<<*a<<' ';cerr<<endl;}
#else
#define dump(x) ;
#define prl ;
template<class T> void debug(T a,T b){ ;}
#endif

template<class T> void chmin(T& a,const T& b) { if(a>b) a=b; }
template<class T> void chmax(T& a,const T& b) { if(a<b) a=b; }
typedef long long int lint;
typedef pair<int,int> pi;

namespace std{
	template<class S,class T>
	ostream &operator <<(ostream& out,const pair<S,T>& a){
		out<<'('<<a.fr<<','<<a.sc<<')';
		return out;
	}
}

lint readL(){
	lint res;
#ifdef ONLINE_JUDGE
	scanf("%I64d",&res);
#else
	scanf("%lld",&res);
#endif
	return res;
}
void printL(lint res){
#ifdef ONLINE_JUDGE
	printf("%I64d",res);
#else
	printf("%lld",res);
#endif
}

//const int INF=5e8;

int h,w;
int buf[35][35];
int goal[35][35];
pi res[1000005];
int mark[35][35];
int cnt;
int sx,sy;

void up(){
	swap(buf[sy][sx],buf[sy-1][sx]);
	--sy;
	res[cnt++]=mp(sy,sx);
}
void down(){
	swap(buf[sy][sx],buf[sy+1][sx]);
	++sy;
	res[cnt++]=mp(sy,sx);
}
void right(){

	swap(buf[sy][sx+1],buf[sy][sx]);
	++sx;
	res[cnt++]=mp(sy,sx);
}
void left(){
	swap(buf[sy][sx-1],buf[sy][sx]);
	--sx;
	res[cnt++]=mp(sy,sx);
}

int id[35][35],curid=1;
pi back[35][35];
void go(int y,int x){
	++curid;
	queue<pi>q;q.push(mp(sy,sx));
	while(!q.empty()){
		pi cur=q.front();q.pop();
		REPN(dx,2,-1) REPN(dy,2,-1) {
			if(dx==0 && dy==0) continue;
			int px=cur.sc+dx,py=cur.fr+dy;
			if(px<0 || py<0 || px>=w || py>=h || mark[py][px] || id[py][px]==curid) continue;
			q.push(mp(py,px));
			id[py][px]=curid;
			back[py][px]=mp(cur.fr,cur.sc);

			if(mp(py,px)==mp(y,x)){
				goto exi4;
			}
		}
	}
exi4:;
	 prl;
	 vector<pi> way;
	 pi cur=mp(y,x);
	 while(cur!=mp(sy,sx)){
		 way.pb(cur);
		 cur=back[cur.fr][cur.sc];
	 }
	 reverse(ALL(way));
	 REP(i,way.size()){
		 swap(buf[way[i].fr][way[i].sc],buf[sy][sx]);
		 sy=way[i].fr;sx=way[i].sc;
		 res[cnt++]=way[i];
	 }
	 sx=x;sy=y;
}

void moveR(int y,int x){
	mark[y][x]=1;
	go(y,x+1);
	left();
	mark[y][x]=0;
}
void moveL(int y,int x){
	mark[y][x]=1;
	go(y,x-1);
	right();
	mark[y][x]=0;
}
void moveD(int y,int x){
	mark[y][x]=1;
	go(y+1,x);
	up();
	mark[y][x]=0;
}

void moveU(int y,int x){
	mark[y][x]=1;
	go(y-1,x);
	down();
	mark[y][x]=0;
}

void end(){
	puts("-1");
	exit(0);
}
void print(){

	printf("%d\n",cnt);
	REP(i,cnt) printf("%d %d\n",res[i].fr+1,res[i].sc+1);
	exit(0);
}

int main(){
	cin>>h>>w;
	REP(i,h) REP(j,w) cin>>buf[i][j];
	REP(i,h) REP(j,w) cin>>goal[i][j];
	if(h<2 || w<2){
		int ar[35]={0},ar2[35]={0};
		int n;
		if(h==1){
			REP(i,w) ar[i]=buf[0][i],ar2[i]=goal[0][i];
			n=w;
		}else{
			REP(i,h) ar[i]=buf[i][0],ar2[i]=goal[i][0];
			n=h;
		}

		REP(i,n) if(ar[i]!=ar2[i]){
			REPN(j,n,i+1) if(ar2[i]==ar[j]){
				dump(i);dump(j);
				rotate(ar+i,ar+j,ar+j+1);

				int fail=0;
				REP(k,n) if(ar[k]!=ar2[k]) fail=1;

				if(!fail){
					for(int k=j;k>=i;--k) res[cnt++]=mp(k,0);
					goto exi3;
				}
				rotate(ar+i,ar+i+1,ar+j+1);
			}
			break;
		}
		end();
exi3:;
	 	if(w==1) ;
		else REP(i,cnt) {
			swap(res[i].fr,res[i].sc);
		}

		print();

	}
	sx=sy=-1;
	REP(i,h) REP(j,w) if(buf[i][j]==goal[h-1][w-1]){
		sy=i;sx=j;
	}
	if(sx==-1) end();
	res[cnt++]=mp(sy,sx);

	REP(i,h-2) REP(j,w){
		pi pos;
		REP(k,h) REP(l,w) if(!mark[k][l] && mp(k,l)!=mp(sy,sx) && goal[i][j]==buf[k][l]){
			pos=mp(k,l);
			goto exi;
		}
		end();
exi:;

		while(pos!=mp(i,j)){
			if(pos.sc<j){
				moveR(pos.fr,pos.sc);++pos.sc;
			}
			else if(pos.sc>j){
				moveL(pos.fr,pos.sc);
				--pos.sc;
			}
			else if(pos.fr>i){
				moveU(pos.fr,pos.sc);
				--pos.fr;
			}
		}
		mark[i][j]=1;
	}

	REP(j,w-1) REPN(i,h,h-2){

		dump(i);dump(j);
		dump(mp(sy,sx));
		pi pos;
		REP(k,h) REP(l,w) if(!mark[k][l] && mp(k,l) != mp(sy,sx) && goal[i][j]==buf[k][l]){
			pos=mp(k,l);
			goto exi2;
		}
		end();
exi2:;
	 dump(pos);

	 	while(pos!=mp(i,j)){
			if(i<pos.fr){
				moveU(pos.fr,pos.sc);
				--pos.fr;
			}
			else if(i>pos.fr) {
				moveD(pos.fr,pos.sc);
				++pos.fr;
			}
			else{
				moveL(pos.fr,pos.sc);
				--pos.sc;
			}
		}
		mark[i][j]=1;
	}

	if(sy<h-1) down();

	if(buf[h-2][w-1]==goal[h-2][w-1]);
	else end();

	print();
	return 0;
}


#include<bits/stdc++.h>
#define REP(i,m) for(int i=0;i<(m);++i)
#define REPN(i,m,in) for(int i=(in);i<(m);++i)
#define ALL(t) (t).begin(),(t).end()
#define CLR(a) memset((a),0,sizeof(a))
#define pb push_back
#define mp make_pair
#define fr first
#define sc second

using namespace std;

#ifndef ONLINE_JUDGE
#define dump(x)  cerr << #x << " = " << (x) << endl
#define prl cerr<<"called:"<< __LINE__<<endl
template<class T> void debug(T a,T b){ for(;a!=b;++a) cerr<<*a<<' ';cerr<<endl;}
#else
#define dump(x) ;
#define prl ;
template<class T> void debug(T a,T b){ ;}
#endif

template<class T> void chmin(T& a,const T& b) { if(a>b) a=b; }
template<class T> void chmax(T& a,const T& b) { if(a<b) a=b; }
typedef long long int lint;
typedef pair<int,int> pi;

namespace std{
	template<class S,class T>
	ostream &operator <<(ostream& out,const pair<S,T>& a){
		out<<'('<<a.fr<<','<<a.sc<<')';
		return out;
	}
}

lint readL(){
	lint res;
#ifdef ONLINE_JUDGE
	scanf("%I64d",&res);
#else
	scanf("%lld",&res);
#endif
	return res;
}
void printL(lint res){
#ifdef ONLINE_JUDGE
	printf("%I64d",res);
#else
	printf("%lld",res);
#endif
}

//const int INF=5e8;

int h,w;
int buf[35][35];
int goal[35][35];
pi res[1000005];
int mark[35][35];
int cnt;
int sx,sy;

void up(){
	swap(buf[sy][sx],buf[sy-1][sx]);
	--sy;
	res[cnt++]=mp(sy,sx);
}
void down(){
	swap(buf[sy][sx],buf[sy+1][sx]);
	++sy;
	res[cnt++]=mp(sy,sx);
}
void right(){

	swap(buf[sy][sx+1],buf[sy][sx]);
	++sx;
	res[cnt++]=mp(sy,sx);
}
void left(){
	swap(buf[sy][sx-1],buf[sy][sx]);
	--sx;
	res[cnt++]=mp(sy,sx);
}

int id[35][35],curid=1;
pi back[35][35];
void go(int y,int x){
	++curid;
	queue<pi>q;q.push(mp(sy,sx));
	while(!q.empty()){
		pi cur=q.front();q.pop();
		REPN(dx,2,-1) REPN(dy,2,-1) {
			if(dx==0 && dy==0) continue;
			int px=cur.sc+dx,py=cur.fr+dy;
			if(px<0 || py<0 || px>=w || py>=h || mark[py][px] || id[py][px]==curid) continue;
			q.push(mp(py,px));
			id[py][px]=curid;
			back[py][px]=mp(cur.fr,cur.sc);

			if(mp(py,px)==mp(y,x)){
				goto exi4;
			}
		}
	}
exi4:;
	 prl;
	 vector<pi> way;
	 pi cur=mp(y,x);
	 while(cur!=mp(sy,sx)){
		 way.pb(cur);
		 cur=back[cur.fr][cur.sc];
	 }
	 reverse(ALL(way));
	 REP(i,way.size()){
		 swap(buf[way[i].fr][way[i].sc],buf[sy][sx]);
		 sy=way[i].fr;sx=way[i].sc;
		 res[cnt++]=way[i];
	 }
	 sx=x;sy=y;
}

void moveR(int y,int x){
	mark[y][x]=1;
	go(y,x+1);
	left();
	mark[y][x]=0;
}
void moveL(int y,int x){
	mark[y][x]=1;
	go(y,x-1);
	right();
	mark[y][x]=0;
}
void moveD(int y,int x){
	mark[y][x]=1;
	go(y+1,x);
	up();
	mark[y][x]=0;
}

void moveU(int y,int x){
	mark[y][x]=1;
	go(y-1,x);
	down();
	mark[y][x]=0;
}

void end(){
	puts("-1");
	exit(0);
}
void print(){

	printf("%d\n",cnt-1);
	REP(i,cnt) printf("%d %d\n",res[i].fr+1,res[i].sc+1);
	exit(0);
}

int main(){
	cin>>h>>w;
	REP(i,h) REP(j,w) cin>>buf[i][j];
	REP(i,h) REP(j,w) cin>>goal[i][j];
	if(h<2 || w<2){
		int ar[35]={0},ar2[35]={0};
		int n;
		if(h==1){
			REP(i,w) ar[i]=buf[0][i],ar2[i]=goal[0][i];
			n=w;
		}else{
			REP(i,h) ar[i]=buf[i][0],ar2[i]=goal[i][0];
			n=h;
		}

		REP(i,n) if(ar[i]!=ar2[i]){
			REPN(j,n,i+1) if(ar2[i]==ar[j]){
				dump(i);dump(j);
				rotate(ar+i,ar+j,ar+j+1);

				int fail=0;
				REP(k,n) if(ar[k]!=ar2[k]) fail=1;

				if(!fail){
					for(int k=j;k>=i;--k) res[cnt++]=mp(k,0);
					goto exi3;
				}
				rotate(ar+i,ar+i+1,ar+j+1);
			}
			REPN(j,n,i+1) if(ar2[j]==ar[i]){
				rotate(ar+i,ar+i+1,ar+j+1);
				int fail=0;
				REP(k,n) if(ar[k]!=ar2[k]) fail=1;

				if(!fail){
					for(int k=i;k<=j;--k) res[cnt++]=mp(k,0);
					goto exi3;
				}
				rotate(ar+i,ar+j,ar+j+1);
			}
			break;
		}
		end();
exi3:;
	 	if(w==1) ;
		else REP(i,cnt) {
			swap(res[i].fr,res[i].sc);
		}

		print();

	}
	sx=sy=-1;
	REP(i,h) REP(j,w) if(buf[i][j]==goal[h-1][w-1]){
		sy=i;sx=j;
	}
	if(sx==-1) end();
	res[cnt++]=mp(sy,sx);

	REP(i,h-2) REP(j,w){
		pi pos;
		REP(k,h) REP(l,w) if(!mark[k][l] && mp(k,l)!=mp(sy,sx) && goal[i][j]==buf[k][l]){
			pos=mp(k,l);
			goto exi;
		}
		end();
exi:;

		while(pos!=mp(i,j)){
			if(pos.sc<j){
				moveR(pos.fr,pos.sc);++pos.sc;
			}
			else if(pos.sc>j){
				moveL(pos.fr,pos.sc);
				--pos.sc;
			}
			else if(pos.fr>i){
				moveU(pos.fr,pos.sc);
				--pos.fr;
			}
		}
		mark[i][j]=1;
	}

	REP(j,w-1) REPN(i,h,h-2){

		dump(i);dump(j);
		dump(mp(sy,sx));
		pi pos;
		REP(k,h) REP(l,w) if(!mark[k][l] && mp(k,l) != mp(sy,sx) && goal[i][j]==buf[k][l]){
			pos=mp(k,l);
			goto exi2;
		}
		end();
exi2:;
	 dump(pos);

	 	while(pos!=mp(i,j)){
			if(i<pos.fr){
				moveU(pos.fr,pos.sc);
				--pos.fr;
			}
			else if(i>pos.fr) {
				moveD(pos.fr,pos.sc);
				++pos.fr;
			}
			else{
				moveL(pos.fr,pos.sc);
				--pos.sc;
			}
		}
		mark[i][j]=1;
	}

	if(sy<h-1) down();

	if(buf[h-2][w-1]==goal[h-2][w-1]);
	else end();

	print();
	return 0;
}


#include<bits/stdc++.h>
#define REP(i,m) for(int i=0;i<(m);++i)
#define REPN(i,m,in) for(int i=(in);i<(m);++i)
#define ALL(t) (t).begin(),(t).end()
#define CLR(a) memset((a),0,sizeof(a))
#define pb push_back
#define mp make_pair
#define fr first
#define sc second

using namespace std;

#ifndef ONLINE_JUDGE
#define dump(x)  cerr << #x << " = " << (x) << endl
#define prl cerr<<"called:"<< __LINE__<<endl
template<class T> void debug(T a,T b){ for(;a!=b;++a) cerr<<*a<<' ';cerr<<endl;}
#else
#define dump(x) ;
#define prl ;
template<class T> void debug(T a,T b){ ;}
#endif

template<class T> void chmin(T& a,const T& b) { if(a>b) a=b; }
template<class T> void chmax(T& a,const T& b) { if(a<b) a=b; }
typedef long long int lint;
typedef pair<int,int> pi;

namespace std{
	template<class S,class T>
	ostream &operator <<(ostream& out,const pair<S,T>& a){
		out<<'('<<a.fr<<','<<a.sc<<')';
		return out;
	}
}

lint readL(){
	lint res;
#ifdef ONLINE_JUDGE
	scanf("%I64d",&res);
#else
	scanf("%lld",&res);
#endif
	return res;
}
void printL(lint res){
#ifdef ONLINE_JUDGE
	printf("%I64d",res);
#else
	printf("%lld",res);
#endif
}

//const int INF=5e8;

int h,w;
int buf[35][35];
int goal[35][35];
pi res[1000005];
int mark[35][35];
int cnt;
int sx,sy;

void up(){
	swap(buf[sy][sx],buf[sy-1][sx]);
	--sy;
	res[cnt++]=mp(sy,sx);
}
void down(){
	swap(buf[sy][sx],buf[sy+1][sx]);
	++sy;
	res[cnt++]=mp(sy,sx);
}
void right(){

	swap(buf[sy][sx+1],buf[sy][sx]);
	++sx;
	res[cnt++]=mp(sy,sx);
}
void left(){
	swap(buf[sy][sx-1],buf[sy][sx]);
	--sx;
	res[cnt++]=mp(sy,sx);
}

int id[35][35],curid=1;
pi back[35][35];
void go(int y,int x){
	++curid;
	queue<pi>q;q.push(mp(sy,sx));
	while(!q.empty()){
		pi cur=q.front();q.pop();
		REPN(dx,2,-1) REPN(dy,2,-1) {
			if(dx==0 && dy==0) continue;
			int px=cur.sc+dx,py=cur.fr+dy;
			if(px<0 || py<0 || px>=w || py>=h || mark[py][px] || id[py][px]==curid) continue;
			q.push(mp(py,px));
			id[py][px]=curid;
			back[py][px]=mp(cur.fr,cur.sc);

			if(mp(py,px)==mp(y,x)){
				goto exi4;
			}
		}
	}
exi4:;
	 prl;
	 vector<pi> way;
	 pi cur=mp(y,x);
	 while(cur!=mp(sy,sx)){
		 way.pb(cur);
		 cur=back[cur.fr][cur.sc];
	 }
	 reverse(ALL(way));
	 REP(i,way.size()){
		 swap(buf[way[i].fr][way[i].sc],buf[sy][sx]);
		 sy=way[i].fr;sx=way[i].sc;
		 res[cnt++]=way[i];
	 }
	 sx=x;sy=y;
}

void moveR(int y,int x){
	mark[y][x]=1;
	go(y,x+1);
	left();
	mark[y][x]=0;
}
void moveL(int y,int x){
	mark[y][x]=1;
	go(y,x-1);
	right();
	mark[y][x]=0;
}
void moveD(int y,int x){
	mark[y][x]=1;
	go(y+1,x);
	up();
	mark[y][x]=0;
}

void moveU(int y,int x){
	mark[y][x]=1;
	go(y-1,x);
	down();
	mark[y][x]=0;
}

void end(){
	puts("-1");
	exit(0);
}
void print(){

	printf("%d\n",cnt-1);
	REP(i,cnt) printf("%d %d\n",res[i].fr+1,res[i].sc+1);
	exit(0);
}

int main(){
	cin>>h>>w;
	REP(i,h) REP(j,w) cin>>buf[i][j];
	REP(i,h) REP(j,w) cin>>goal[i][j];
	if(h<2 || w<2){
		int ar[35]={0},ar2[35]={0};
		int n;
		if(h==1){
			REP(i,w) ar[i]=buf[0][i],ar2[i]=goal[0][i];
			n=w;
		}else{
			REP(i,h) ar[i]=buf[i][0],ar2[i]=goal[i][0];
			n=h;
		}

		REP(i,n) if(ar[i]!=ar2[i]){
			REPN(j,n,i+1) if(ar2[i]==ar[j]){
				dump(i);dump(j);
				rotate(ar+i,ar+j,ar+j+1);

				int fail=0;
				REP(k,n) if(ar[k]!=ar2[k]) fail=1;

				if(!fail){
					for(int k=j;k>=i;--k) res[cnt++]=mp(k,0);
					goto exi3;
				}
				rotate(ar+i,ar+i+1,ar+j+1);
			}
			break;
		}
		end();
exi3:;
	 	if(w==1) ;
		else REP(i,cnt) {
			swap(res[i].fr,res[i].sc);
		}

		print();

	}
	sx=sy=-1;
	REP(i,h) REP(j,w) if(buf[i][j]==goal[h-1][w-1]){
		sy=i;sx=j;
	}
	if(sx==-1) end();
	res[cnt++]=mp(sy,sx);

	REP(i,h-2) REP(j,w){
		pi pos;
		REP(k,h) REP(l,w) if(!mark[k][l] && mp(k,l)!=mp(sy,sx) && goal[i][j]==buf[k][l]){
			pos=mp(k,l);
			goto exi;
		}
		end();
exi:;

		while(pos!=mp(i,j)){
			if(pos.sc<j){
				moveR(pos.fr,pos.sc);++pos.sc;
			}
			else if(pos.sc>j){
				moveL(pos.fr,pos.sc);
				--pos.sc;
			}
			else if(pos.fr>i){
				moveU(pos.fr,pos.sc);
				--pos.fr;
			}
		}
		mark[i][j]=1;
	}

	REP(j,w-1) REPN(i,h,h-2){

		dump(i);dump(j);
		dump(mp(sy,sx));
		pi pos;
		REP(k,h) REP(l,w) if(!mark[k][l] && mp(k,l) != mp(sy,sx) && goal[i][j]==buf[k][l]){
			pos=mp(k,l);
			goto exi2;
		}
		end();
exi2:;
	 dump(pos);

	 	while(pos!=mp(i,j)){
			if(i<pos.fr){
				moveU(pos.fr,pos.sc);
				--pos.fr;
			}
			else if(i>pos.fr) {
				moveD(pos.fr,pos.sc);
				++pos.fr;
			}
			else{
				moveL(pos.fr,pos.sc);
				--pos.sc;
			}
		}
		mark[i][j]=1;
	}

	if(sy<h-1) down();

	if(buf[h-2][w-1]==goal[h-2][w-1]);
	else end();

	print();
	return 0;
}


#include<bits/stdc++.h>
#define REP(i,m) for(int i=0;i<(m);++i)
#define REPN(i,m,in) for(int i=(in);i<(m);++i)
#define ALL(t) (t).begin(),(t).end()
#define CLR(a) memset((a),0,sizeof(a))
#define pb push_back
#define mp make_pair
#define fr first
#define sc second

using namespace std;

#ifndef ONLINE_JUDGE
#define dump(x)  cerr << #x << " = " << (x) << endl
#define prl cerr<<"called:"<< __LINE__<<endl
template<class T> void debug(T a,T b){ for(;a!=b;++a) cerr<<*a<<' ';cerr<<endl;}
#else
#define dump(x) ;
#define prl ;
template<class T> void debug(T a,T b){ ;}
#endif

template<class T> void chmin(T& a,const T& b) { if(a>b) a=b; }
template<class T> void chmax(T& a,const T& b) { if(a<b) a=b; }
typedef long long int lint;
typedef pair<int,int> pi;

namespace std{
	template<class S,class T>
	ostream &operator <<(ostream& out,const pair<S,T>& a){
		out<<'('<<a.fr<<','<<a.sc<<')';
		return out;
	}
}

lint readL(){
	lint res;
#ifdef ONLINE_JUDGE
	scanf("%I64d",&res);
#else
	scanf("%lld",&res);
#endif
	return res;
}
void printL(lint res){
#ifdef ONLINE_JUDGE
	printf("%I64d",res);
#else
	printf("%lld",res);
#endif
}

//const int INF=5e8;

int h,w;
int buf[35][35];
int goal[35][35];
pi res[1000005];
int mark[35][35];
int cnt;
int sx,sy;

void up(){
	swap(buf[sy][sx],buf[sy-1][sx]);
	--sy;
	res[cnt++]=mp(sy,sx);
}
void down(){
	swap(buf[sy][sx],buf[sy+1][sx]);
	++sy;
	res[cnt++]=mp(sy,sx);
}
void right(){

	swap(buf[sy][sx+1],buf[sy][sx]);
	++sx;
	res[cnt++]=mp(sy,sx);
}
void left(){
	swap(buf[sy][sx-1],buf[sy][sx]);
	--sx;
	res[cnt++]=mp(sy,sx);
}

int id[35][35],curid=1;
pi back[35][35];
void go(int y,int x){
	++curid;
	queue<pi>q;q.push(mp(sy,sx));
	while(!q.empty()){
		pi cur=q.front();q.pop();
		REPN(dx,2,-1) REPN(dy,2,-1) {
			if(dx==0 && dy==0) continue;
			int px=cur.sc+dx,py=cur.fr+dy;
			if(px<0 || py<0 || px>=w || py>=h || mark[py][px] || id[py][px]==curid) continue;
			q.push(mp(py,px));
			id[py][px]=curid;
			back[py][px]=mp(cur.fr,cur.sc);

			if(mp(py,px)==mp(y,x)){
				goto exi4;
			}
		}
	}
exi4:;
	 prl;
	 vector<pi> way;
	 pi cur=mp(y,x);
	 while(cur!=mp(sy,sx)){
		 way.pb(cur);
		 cur=back[cur.fr][cur.sc];
	 }
	 reverse(ALL(way));
	 REP(i,way.size()){
		 swap(buf[way[i].fr][way[i].sc],buf[sy][sx]);
		 sy=way[i].fr;sx=way[i].sc;
		 res[cnt++]=way[i];
	 }
	 sx=x;sy=y;
}

void moveR(int y,int x){
	mark[y][x]=1;
	go(y,x+1);
	left();
	mark[y][x]=0;
}
void moveL(int y,int x){
	mark[y][x]=1;
	go(y,x-1);
	right();
	mark[y][x]=0;
}
void moveD(int y,int x){
	mark[y][x]=1;
	go(y+1,x);
	up();
	mark[y][x]=0;
}

void moveU(int y,int x){
	mark[y][x]=1;
	go(y-1,x);
	down();
	mark[y][x]=0;
}

void end(){
	puts("-1");
	exit(0);
}
void print(){

	printf("%d\n",cnt-1);
	REP(i,cnt) printf("%d %d\n",res[i].fr+1,res[i].sc+1);
	exit(0);
}

int main(){
	cin>>h>>w;
	REP(i,h) REP(j,w) cin>>buf[i][j];
	REP(i,h) REP(j,w) cin>>goal[i][j];
	if(h<2 || w<2){
		int ar[35]={0},ar2[35]={0};
		int n;
		if(h==1){
			REP(i,w) ar[i]=buf[0][i],ar2[i]=goal[0][i];
			n=w;
		}else{
			REP(i,h) ar[i]=buf[i][0],ar2[i]=goal[i][0];
			n=h;
		}

		REP(i,n) if(ar[i]!=ar2[i]){
			REPN(j,n,i+1) if(ar2[i]==ar[j]){
				dump(i);dump(j);
				rotate(ar+i,ar+j,ar+j+1);

				int fail=0;
				REP(k,n) if(ar[k]!=ar2[k]) fail=1;

				if(!fail){
					for(int k=j;k>=i;--k) res[cnt++]=mp(k,0);
					goto exi3;
				}
				rotate(ar+i,ar+i+1,ar+j+1);
			}
			REPN(j,n,i+1) if(ar2[j]==ar[i]){
				rotate(ar+i,ar+i+1,ar+j+1);
				int fail=0;
				REP(k,n) if(ar[k]!=ar2[k]) fail=1;

				if(!fail){
					for(int k=j;k>=i;--k) res[cnt++]=mp(k,0);
					goto exi3;
				}
				rotate(ar+i,ar+j,ar+j+1);
			}
			break;
		}
		end();
exi3:;
	 	if(w==1) ;
		else REP(i,cnt) {
			swap(res[i].fr,res[i].sc);
		}

		print();

	}
	sx=sy=-1;
	REP(i,h) REP(j,w) if(buf[i][j]==goal[h-1][w-1]){
		sy=i;sx=j;
	}
	if(sx==-1) end();
	res[cnt++]=mp(sy,sx);

	REP(i,h-2) REP(j,w){
		pi pos;
		REP(k,h) REP(l,w) if(!mark[k][l] && mp(k,l)!=mp(sy,sx) && goal[i][j]==buf[k][l]){
			pos=mp(k,l);
			goto exi;
		}
		end();
exi:;

		while(pos!=mp(i,j)){
			if(pos.sc<j){
				moveR(pos.fr,pos.sc);++pos.sc;
			}
			else if(pos.sc>j){
				moveL(pos.fr,pos.sc);
				--pos.sc;
			}
			else if(pos.fr>i){
				moveU(pos.fr,pos.sc);
				--pos.fr;
			}
		}
		mark[i][j]=1;
	}

	REP(j,w-1) REPN(i,h,h-2){

		dump(i);dump(j);
		dump(mp(sy,sx));
		pi pos;
		REP(k,h) REP(l,w) if(!mark[k][l] && mp(k,l) != mp(sy,sx) && goal[i][j]==buf[k][l]){
			pos=mp(k,l);
			goto exi2;
		}
		end();
exi2:;
	 dump(pos);

	 	while(pos!=mp(i,j)){
			if(i<pos.fr){
				moveU(pos.fr,pos.sc);
				--pos.fr;
			}
			else if(i>pos.fr) {
				moveD(pos.fr,pos.sc);
				++pos.fr;
			}
			else{
				moveL(pos.fr,pos.sc);
				--pos.sc;
			}
		}
		mark[i][j]=1;
	}

	if(sy<h-1) down();

	if(buf[h-2][w-1]==goal[h-2][w-1]);
	else end();

	print();
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define _SZ(n) memset((n),0,sizeof(n))
#define _SMO(n) memset((n),-1,sizeof(n))
#define _MC(n,m) memcpy((n),(m),sizeof(n))
#define _F first
#define _S second
#define _MP make_pair
#define _PB push_back
#define FOR(x,y) for(__typeof(y.begin())x=y.begin();x!=y.end();x++)
#define IOS ios_base::sync_with_stdio(0)
#ifdef ONLINE_JUDGE
#define FILEIO(name) \
  freopen(name".in", "r", stdin); \
  freopen(name".out", "w", stdout);
#else
#define FILEIO(name)
#endif
// Let's Fight!

const int MX = 35;

struct Point{
  int x,y;
  Point () {}
  Point (int _x, int _y) : x(_x), y(_y) {}
  bool operator == (const Point &b) const{
    return x == b.x && y == b.y;
  }
  bool operator != (const Point &b) const{
    return !(*this == b);
  }
};

int N,M,ip[MX][MX],op[MX][MX];
Point p(-1,-1), q; // p move q to ed
vector<Point> ans;
vector<Point> seq;
int bad[MX][MX];
Point prv[MX][MX];
Point que[MX*MX];
int vst[MX][MX];
int fr,bk;
int dir[8][2] = {{-1,0},{1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}};
vector<Point> path;

void BFS(Point ed){
//  printf("BFS %d %d -> %d %d\n", p.x, p.y, ed.x, ed.y);
  fr = bk = 0;
  _SZ(vst);
  que[bk++] = p;
  vst[p.x][p.y] = 1;
  while (fr < bk){
    Point u = que[fr++];
    for (int i=0; i<8; i++){
      int nx = u.x + dir[i][0];
      int ny = u.y + dir[i][1];
      if (nx < 1 || ny < 1 || nx > N || ny > M) continue;
      if (bad[nx][ny]) continue;
      if (q.x == nx && q.y == ny) continue;
      if (vst[nx][ny]) continue;
      que[bk++] = Point(nx,ny);
      prv[nx][ny] = u;
      vst[nx][ny] = 1;
    }
    if (vst[ed.x][ed.y]) break;
  }
  assert(vst[ed.x][ed.y] == 1);
  path.clear();
  Point cur = ed;
  while (cur != p){
    path._PB(cur);
    cur = prv[cur.x][cur.y];
  }
  reverse(path.begin(),path.end());
}
void move(Point a){
  ans._PB(a);
  swap(ip[a.x][a.y],ip[p.x][p.y]);
  p = a;
}
void solve(Point ed){
  if (ip[ed.x][ed.y] == op[ed.x][ed.y]) return ;
  q = Point(-1,-1);
  for (int i=1; i<=N && q.x==-1; i++){
    for (int j=1; j<=M && q.x==-1; j++){
      if (bad[i][j]) continue;
      if (p.x == i && p.y == j) continue;
      if (ip[i][j] == op[ed.x][ed.y])
        q = Point(i,j);
    }
  }
  while (q.x != ed.x){
    while (q.x > ed.x){
      BFS(Point(q.x-1,q.y));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
    while (q.x < ed.x){
      BFS(Point(q.x+1,q.y));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
  }
  while (q.y != ed.y){
    while (q.y > ed.y){
      BFS(Point(q.x,q.y-1));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
    while (q.y < ed.y){
      BFS(Point(q.x,q.y+1));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
  }
}
void solve_seq(){
  for (auto v : seq){
//    printf("solving %d %d\n", v.x , v.y);
    solve(v);
    bad[v.x][v.y] = 1;
  }
}
void solve22(){
  if (p != Point(1,1)){
    move(Point(1,1));
  }
  if (ip[2][2] != op[2][2]){
    if (ip[1][2] == op[2][2]){
      move(Point(2,2));
      move(Point(1,2));
    } else if (ip[2][1] == op[2][2]){
      move(Point(2,2));
      move(Point(2,1));
    }
  }
  if (p != Point(1,1)){
    move(Point(1,1));
  }
  if (ip[1][2] != op[1][2]){
    move(Point(2,1));
    move(Point(1,2));
  }
  if (p != Point(1,1)){
    move(Point(1,1));
  }
}
int main()
{
  int c1[MX*MX] = {0};
  int c2[MX*MX] = {0};
  scanf("%d%d", &N, &M);
  for (int i=1; i<=N; i++){
    for (int j=1; j<=M; j++){
      scanf("%d", &ip[i][j]);
      c1[ip[i][j]]++;
    }
  }
  for (int i=1; i<=N; i++){
    for (int j=1; j<=M; j++){
      scanf("%d", &op[i][j]);
      c2[op[i][j]]++;
    }
  }
  for (int i=1; i<MX*MX; i++){
    if (c1[i] != c2[i]){
      puts("-1");
      return 0;
    }
  }
  if (N == 1){
    int sy = -1;
    int ey = -1;
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j]){
        if (sy == -1){
          sy = j;
        }
        ey = j;
      }
    }
    if (sy == -1){
      puts("0");
      puts("1 1");
      return 0;
    }
    int fail=0;
    // check sy -> ey
    for (int j=sy; j<ey; j++)
      swap(ip[1][j],ip[1][j+1]);
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j])
        fail = 1;
    }
    if (!fail){
      printf("%d\n", ey-sy);
      for (int j=sy; j<=ey; j++)
        printf("%d %d\n", 1, j);
      return 0;
    }
    for (int j=ey; j>sy; j--)
      swap(ip[1][j],ip[1][j-1]);
    // check ey -> sy
    fail = 0;
    for (int j=ey; j>sy; j--)
      swap(ip[1][j],ip[1][j-1]);
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j])
        fail = 1;
    }
    if (!fail){
      printf("%d\n", ey-sy);
      for (int j=ey; j>=sy; j--)
        printf("%d %d\n", 1, j);
    } else {
      puts("-1");
    }
    return 0;
  } else if (M == 1){
    int sx = -1;
    int ex = -1;
    for (int i=1; i<=N; i++){
      if (ip[i][1] != op[i][1]){
        if (sx == -1){
          sx = i;
        }
        ex = i;
      }
    }
    if (sx == -1){
      puts("0");
      puts("1 1");
      return 0;
    }
    int fail = 0;
    // check sx -> ex
    for (int i=sx; i<ex; i++)
      swap(ip[i][1],ip[i+1][1]);
    for (int i=1; i<=N; i++)
      if (ip[i][1] != op[i][1])
        fail = 1;
    if (!fail){
      printf("%d\n", ex-sx);
      for (int i=sx; i<=ex; i++)
        printf("%d %d\n", i, 1);
      return 0;
    }
    for (int i=ex; i>sx; i--)
      swap(ip[i][1],ip[i-1][1]);
    // check ex -> sx
    for (int i=ex; i>sx; i--)
      swap(ip[i][1], ip[i-1][1]);
    fail = 0;
    for (int i=1; i<=N; i++)
      if (ip[i][1] != op[i][1])
        fail = 1;
    if (!fail){
      printf("%d\n", ex-sx);
      for (int i=ex; i>=sx; i--)
        printf("%d %d\n", i, 1);
    } else {
      puts("-1");
    }
  } else {
    p = Point(-1,-1);
    for (int i=1; i<=N && p.x == -1; i++){
      for (int j=1; j<=M && p.x == -1; j++){
        if (ip[i][j] == op[1][1]){
          p = Point(i,j);
        }
      }
    }
    int x = p.x;
    int y = p.y;
//    printf("st = (%d, %d)\n", x, y);
    for (int j=M; j>2; j--){
      for (int i=N; i>=1; i--){
        seq._PB(Point(i,j));
      }
    }
    for (int i=N; i>2; i--){
      seq._PB(Point(i,2));
      seq._PB(Point(i,1));
    }
    _SZ(bad);
    /*
    puts("seq : ");
    for (auto i : seq)
      printf("%d %d\n", i.x, i.y);
    puts("==");
    */
    solve_seq();

    for (int i=1; i<=N; i++){
      for (int j=1; j<=M; j++){
        //printf("%d ", ip[i][j]);
        if (i>2 && j>2 && ip[i][j] != op[i][j]){
          assert(false);
        }
      }
     //puts("");
    }

    solve22();
    for (int i=1; i<=N; i++){
      for (int j=1; j<=M; j++){
        if (ip[i][j] != op[i][j]){
          assert(false);
          //printf("fail @ %d %d\n", i, j);
          exit(0);
        }
      }
    }
    assert(ans.size() <= 1000000);
    printf("%d\n", (int)ans.size());
    printf("%d %d\n", x, y);
    for (auto i : ans)
      printf("%d %d\n", i.x, i.y);
  }

  return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define _SZ(n) memset((n),0,sizeof(n))
#define _SMO(n) memset((n),-1,sizeof(n))
#define _MC(n,m) memcpy((n),(m),sizeof(n))
#define _F first
#define _S second
#define _MP make_pair
#define _PB push_back
#define FOR(x,y) for(__typeof(y.begin())x=y.begin();x!=y.end();x++)
#define IOS ios_base::sync_with_stdio(0)
#ifdef ONLINE_JUDGE
#define FILEIO(name) \
  freopen(name".in", "r", stdin); \
  freopen(name".out", "w", stdout);
#else
#define FILEIO(name)
#endif
// Let's Fight!

const int MX = 35;

struct Point{
  int x,y;
  Point () {}
  Point (int _x, int _y) : x(_x), y(_y) {}
  bool operator == (const Point &b) const{
    return x == b.x && y == b.y;
  }
  bool operator != (const Point &b) const{
    return !(*this == b);
  }
};

int N,M,ip[MX][MX],op[MX][MX];
Point p(-1,-1), q; // p move q to ed
vector<Point> ans;
vector<Point> seq;
int bad[MX][MX];
Point prv[MX][MX];
Point que[MX*MX];
int vst[MX][MX];
int fr,bk;
int dir[8][2] = {{-1,0},{1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}};
vector<Point> path;

void BFS(Point ed){
//  printf("BFS %d %d -> %d %d\n", p.x, p.y, ed.x, ed.y);
  fr = bk = 0;
  _SZ(vst);
  que[bk++] = p;
  vst[p.x][p.y] = 1;
  while (fr < bk){
    Point u = que[fr++];
    for (int i=0; i<8; i++){
      int nx = u.x + dir[i][0];
      int ny = u.y + dir[i][1];
      if (nx < 1 || ny < 1 || nx > N || ny > M) continue;
      if (bad[nx][ny]) continue;
      if (q.x == nx && q.y == ny) continue;
      if (vst[nx][ny]) continue;
      que[bk++] = Point(nx,ny);
      prv[nx][ny] = u;
      vst[nx][ny] = 1;
    }
    if (vst[ed.x][ed.y]) break;
  }
  assert(vst[ed.x][ed.y] == 1);
  path.clear();
  Point cur = ed;
  while (cur != p){
    path._PB(cur);
    cur = prv[cur.x][cur.y];
  }
  reverse(path.begin(),path.end());
}
void move(Point a){
  ans._PB(a);
  swap(ip[a.x][a.y],ip[p.x][p.y]);
  p = a;
}
void solve(Point ed){
  if (ip[ed.x][ed.y] == op[ed.x][ed.y]) return ;
  q = Point(-1,-1);
  for (int i=1; i<=N && q.x==-1; i++){
    for (int j=1; j<=M && q.x==-1; j++){
      if (bad[i][j]) continue;
      if (p.x == i && p.y == j) continue;
      if (ip[i][j] == op[ed.x][ed.y])
        q = Point(i,j);
    }
  }
  while (q.x != ed.x){
    while (q.x > ed.x){
      BFS(Point(q.x-1,q.y));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
    while (q.x < ed.x){
      BFS(Point(q.x+1,q.y));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
  }
  while (q.y != ed.y){
    while (q.y > ed.y){
      BFS(Point(q.x,q.y-1));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
    while (q.y < ed.y){
      BFS(Point(q.x,q.y+1));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
  }
}
void solve_seq(){
  for (auto v : seq){
//    printf("solving %d %d\n", v.x , v.y);
    solve(v);
    bad[v.x][v.y] = 1;
  }
}
void solve22(){
  if (p != Point(1,1)){
    move(Point(1,1));
  }
  if (ip[2][2] != op[2][2]){
    if (ip[1][2] == op[2][2]){
      move(Point(2,2));
      move(Point(1,2));
    } else if (ip[2][1] == op[2][2]){
      move(Point(2,2));
      move(Point(2,1));
    }
  }
  if (p != Point(1,1)){
    move(Point(1,1));
  }
  if (ip[1][2] != op[1][2]){
    move(Point(2,1));
    move(Point(1,2));
  }
  if (p != Point(1,1)){
    move(Point(1,1));
  }
}
int main()
{
  int c1[MX*MX] = {0};
  int c2[MX*MX] = {0};
  scanf("%d%d", &N, &M);
  for (int i=1; i<=N; i++){
    for (int j=1; j<=M; j++){
      scanf("%d", &ip[i][j]);
      c1[ip[i][j]]++;
    }
  }
  for (int i=1; i<=N; i++){
    for (int j=1; j<=M; j++){
      scanf("%d", &op[i][j]);
      c2[op[i][j]]++;
    }
  }
  for (int i=1; i<MX*MX; i++){
    if (c1[i] != c2[i]){
      puts("-1");
      return 0;
    }
  }
  if (N == 1){
    int sy = -1;
    int ey = -1;
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j]){
        if (sy == -1){
          sy = j;
        }
        ey = j;
      }
    }
    if (sy == -1){
      puts("0");
      puts("1 1");
      return 0;
    }
    int fail=0;
    // check sy -> ey
    for (int j=sy; j<ey; j++)
      swap(ip[1][j],ip[1][j+1]);
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j])
        fail = 1;
    }
    if (!fail){
      printf("%d\n", ey-sy);
      for (int j=sy; j<=ey; j++)
        printf("%d %d\n", 1, j);
      return 0;
    }
    for (int j=ey; j>sy; j--)
      swap(ip[1][j],ip[1][j-1]);
    // check ey -> sy
    fail = 0;
    for (int j=ey; j>sy; j--)
      swap(ip[1][j],ip[1][j-1]);
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j])
        fail = 1;
    }
    if (!fail){
      printf("%d\n", ey-sy);
      for (int j=ey; j>=sy; j--)
        printf("%d %d\n", 1, j);
    } else {
      puts("-1");
    }
    return 0;
  } else if (M == 1){
    int sx = -1;
    int ex = -1;
    for (int i=1; i<=N; i++){
      if (ip[i][1] != op[i][1]){
        if (sx == -1){
          sx = i;
        }
        ex = i;
      }
    }
    if (sx == -1){
      puts("0");
      puts("1 1");
      return 0;
    }
    int fail = 0;
    // check sx -> ex
    for (int i=sx; i<ex; i++)
      swap(ip[i][1],ip[i+1][1]);
    for (int i=1; i<=N; i++)
      if (ip[i][1] != op[i][1])
        fail = 1;
    if (!fail){
      printf("%d\n", ex-sx);
      for (int i=sx; i<=ex; i++)
        printf("%d %d\n", i, 1);
      return 0;
    }
    for (int i=ex; i>sx; i--)
      swap(ip[i][1],ip[i-1][1]);
    // check ex -> sx
    for (int i=ex; i>sx; i--)
      swap(ip[i][1], ip[i-1][1]);
    fail = 0;
    for (int i=1; i<=N; i++)
      if (ip[i][1] != op[i][1])
        fail = 1;
    if (!fail){
      printf("%d\n", ex-sx);
      for (int i=ex; i>=sx; i--)
        printf("%d %d\n", i, 1);
    } else {
      puts("-1");
    }
  } else {
    p = Point(-1,-1);
    for (int i=1; i<=N && p.x == -1; i++){
      for (int j=1; j<=M && p.x == -1; j++){
        if (ip[i][j] == op[1][1]){
          p = Point(i,j);
        }
      }
    }
    int x = p.x;
    int y = p.y;
//    printf("st = (%d, %d)\n", x, y);
    for (int j=M; j>2; j--){
      for (int i=N; i>=1; i--){
        seq._PB(Point(i,j));
      }
    }
    for (int i=N; i>2; i--){
      seq._PB(Point(i,2));
      seq._PB(Point(i,1));
    }
    _SZ(bad);
    /*
    puts("seq : ");
    for (auto i : seq)
      printf("%d %d\n", i.x, i.y);
    puts("==");
    */
    solve_seq();
    /*
    for (int i=1; i<=N; i++){
      for (int j=1; j<=M; j++){
        printf("%d ", ip[i][j]);
        if (i>2 && j>2 && ip[i][j] != op[i][j]){
          puts("FAIL QAQ");
        }
      }
      puts("");
    }
    */
    solve22();
    for (int i=1; i<=N; i++){
      for (int j=1; j<=M; j++){
        if (ip[i][j] != op[i][j]){
          printf("fail @ %d %d\n", i, j);
          exit(0);
        }
      }
    }
    assert(ans.size() <= 1000000);
    printf("%d\n", (int)ans.size());
    printf("%d %d\n", x, y);
    for (auto i : ans)
      printf("%d %d\n", i.x, i.y);
  }

  return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define _SZ(n) memset((n),0,sizeof(n))
#define _SMO(n) memset((n),-1,sizeof(n))
#define _MC(n,m) memcpy((n),(m),sizeof(n))
#define _F first
#define _S second
#define _MP make_pair
#define _PB push_back
#define FOR(x,y) for(__typeof(y.begin())x=y.begin();x!=y.end();x++)
#define IOS ios_base::sync_with_stdio(0)
#ifdef ONLINE_JUDGE
#define FILEIO(name) \
  freopen(name".in", "r", stdin); \
  freopen(name".out", "w", stdout);
#else
#define FILEIO(name)
#endif
// Let's Fight!

const int MX = 35;

struct Point{
  int x,y;
  Point () {}
  Point (int _x, int _y) : x(_x), y(_y) {}
  bool operator == (const Point &b) const{
    return x == b.x && y == b.y;
  }
  bool operator != (const Point &b) const{
    return !(*this == b);
  }
};

int N,M,ip[MX][MX],op[MX][MX];
Point p(-1,-1), q; // p move q to ed
vector<Point> ans;
vector<Point> seq;
int bad[MX][MX];
Point prv[MX][MX];
Point que[MX*MX];
int vst[MX][MX];
int fr,bk;
int dir[8][2] = {{-1,0},{1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}};
vector<Point> path;

void BFS(Point ed){
//  printf("BFS %d %d -> %d %d\n", p.x, p.y, ed.x, ed.y);
  fr = bk = 0;
  _SZ(vst);
  que[bk++] = p;
  vst[p.x][p.y] = 1;
  while (fr < bk){
    Point u = que[fr++];
    for (int i=0; i<8; i++){
      int nx = u.x + dir[i][0];
      int ny = u.y + dir[i][1];
      if (nx < 1 || ny < 1 || nx > N || ny > M) continue;
      if (bad[nx][ny]) continue;
      if (q.x == nx && q.y == ny) continue;
      if (vst[nx][ny]) continue;
      que[bk++] = Point(nx,ny);
      prv[nx][ny] = u;
      vst[nx][ny] = 1;
    }
    if (vst[ed.x][ed.y]) break;
  }
  assert(vst[ed.x][ed.y] == 1);
  path.clear();
  Point cur = ed;
  while (cur != p){
    path._PB(cur);
    cur = prv[cur.x][cur.y];
  }
  reverse(path.begin(),path.end());
}
void move(Point a){
  ans._PB(a);
  swap(ip[a.x][a.y],ip[p.x][p.y]);
  p = a;
}
void solve(Point ed){
  if (ip[ed.x][ed.y] == op[ed.x][ed.y]) return ;
  q = Point(-1,-1);
  for (int i=1; i<=N && q.x==-1; i++){
    for (int j=1; j<=M && q.x==-1; j++){
      if (bad[i][j]) continue;
      if (p.x == i && p.y == j) continue;
      if (ip[i][j] == op[ed.x][ed.y])
        q = Point(i,j);
    }
  }
  while (q.x != ed.x){
    while (q.x > ed.x){
      BFS(Point(q.x-1,q.y));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
    while (q.x < ed.x){
      BFS(Point(q.x+1,q.y));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
  }
  while (q.y != ed.y){
    while (q.y > ed.y){
      BFS(Point(q.x,q.y-1));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
    while (q.y < ed.y){
      BFS(Point(q.x,q.y+1));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
  }
}
void solve_seq(){
  for (auto v : seq){
//    printf("solving %d %d\n", v.x , v.y);
    solve(v);
    bad[v.x][v.y] = 1;
  }
}
void solve22(){
  if (p != Point(1,1)){
    move(Point(1,1));
  }
  if (ip[2][2] != op[2][2]){
    if (ip[1][2] == op[2][2]){
      move(Point(2,2));
      move(Point(1,2));
    } else if (ip[2][1] == op[2][2]){
      move(Point(2,2));
      move(Point(2,1));
    }
  }
  if (p != Point(1,1)){
    move(Point(1,1));
  }
  if (ip[1][2] != op[1][2]){
    move(Point(2,1));
    move(Point(1,2));
  }
  if (p != Point(1,1)){
    move(Point(1,1));
  }
}
int main()
{
  int c1[MX*MX] = {0};
  int c2[MX*MX] = {0};
  scanf("%d%d", &N, &M);
  for (int i=1; i<=N; i++){
    for (int j=1; j<=M; j++){
      scanf("%d", &ip[i][j]);
      c1[ip[i][j]]++;
    }
  }
  for (int i=1; i<=N; i++){
    for (int j=1; j<=M; j++){
      scanf("%d", &op[i][j]);
      c2[op[i][j]]++;
    }
  }
  for (int i=1; i<MX*MX; i++){
    if (c1[i] != c2[i]){
      puts("-1");
      return 0;
    }
  }
  if (N == 1){
    int sy = -1;
    int ey = -1;
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j]){
        if (sy == -1){
          sy = j;
        }
        ey = j;
      }
    }
    if (sy == -1){
      puts("0");
      puts("1 1");
      return 0;
    }
    int fail=0;
    // check sy -> ey
    for (int j=sy; j<ey; j++)
      swap(ip[1][j],ip[1][j+1]);
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j])
        fail = 1;
    }
    if (!fail){
      printf("%d\n", ey-sy);
      for (int j=sy; j<=ey; j++)
        printf("%d %d\n", 1, j);
      return 0;
    }
    for (int j=ey; j>sy; j--)
      swap(ip[1][j],ip[1][j-1]);
    // check ey -> sy
    fail = 0;
    for (int j=ey; j>sy; j--)
      swap(ip[1][j],ip[1][j-1]);
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j])
        fail = 1;
    }
    if (!fail){
      printf("%d\n", ey-sy);
      for (int j=ey; j>=sy; j--)
        printf("%d %d\n", 1, j);
    } else {
      puts("-1");
    }
    return 0;
  } else if (M == 1){
    int sx = -1;
    int ex = -1;
    for (int i=1; i<=N; i++){
      if (ip[i][1] != op[i][1]){
        if (sx == -1){
          sx = i;
        }
        ex = i;
      }
    }
    if (sx == -1){
      puts("0");
      puts("1 1");
      return 0;
    }
    int fail = 0;
    // check sx -> ex
    for (int i=sx; i<ex; i++)
      swap(ip[i][1],ip[i+1][1]);
    for (int i=1; i<=N; i++)
      if (ip[i][1] != op[i][1])
        fail = 1;
    if (!fail){
      printf("%d\n", ex-sx);
      for (int i=sx; i<=ex; i++)
        printf("%d %d\n", i, 1);
      return 0;
    }
    for (int i=ex; i>sx; i--)
      swap(ip[i][1],ip[i-1][1]);
    // check ex -> sx
    for (int i=ex; i>sx; i--)
      swap(ip[i][1], ip[i-1][1]);
    fail = 0;
    for (int i=1; i<=N; i++)
      if (ip[i][1] != op[i][1])
        fail = 1;
    if (!fail){
      printf("%d\n", ex-sx);
      for (int i=ex; i>=sx; i--)
        printf("%d %d\n", i, 1);
    } else {
      puts("-1");
    }
    return 0;
  } else {
    p = Point(-1,-1);
    for (int i=1; i<=N && p.x == -1; i++){
      for (int j=1; j<=M && p.x == -1; j++){
        if (ip[i][j] == op[1][1]){
          p = Point(i,j);
        }
      }
    }
    int x = p.x;
    int y = p.y;
//    printf("st = (%d, %d)\n", x, y);
    for (int j=M; j>2; j--){
      for (int i=N; i>=1; i--){
        seq._PB(Point(i,j));
      }
    }
    for (int i=N; i>2; i--){
      seq._PB(Point(i,2));
      seq._PB(Point(i,1));
    }
    _SZ(bad);
    /*
    puts("seq : ");
    for (auto i : seq)
      printf("%d %d\n", i.x, i.y);
    puts("==");
    */
    solve_seq();

    for (int i=1; i<=N; i++){
      for (int j=1; j<=M; j++){
        //printf("%d ", ip[i][j]);
        if (i>2 && j>2 && ip[i][j] != op[i][j]){
          assert(false);
        }
      }
     //puts("");
    }

    solve22();
    for (int i=1; i<=N; i++){
      for (int j=1; j<=M; j++){
        if (ip[i][j] != op[i][j]){
          assert(false);
          //printf("fail @ %d %d\n", i, j);
        }
      }
    }
    assert(ans.size() <= 1000000);
    printf("%d\n", (int)ans.size());
    printf("%d %d\n", x, y);
    for (auto i : ans)
      printf("%d %d\n", i.x, i.y);
  }

  return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define _SZ(n) memset((n),0,sizeof(n))
#define _SMO(n) memset((n),-1,sizeof(n))
#define _MC(n,m) memcpy((n),(m),sizeof(n))
#define _F first
#define _S second
#define _MP make_pair
#define _PB push_back
#define FOR(x,y) for(__typeof(y.begin())x=y.begin();x!=y.end();x++)
#define IOS ios_base::sync_with_stdio(0)
#ifdef ONLINE_JUDGE
#define FILEIO(name) \
  freopen(name".in", "r", stdin); \
  freopen(name".out", "w", stdout);
#else
#define FILEIO(name)
#endif
// Let's Fight!

const int MX = 35;

struct Point{
  int x,y;
  Point () {}
  Point (int _x, int _y) : x(_x), y(_y) {}
  bool operator == (const Point &b) const{
    return x == b.x && y == b.y;
  }
  bool operator != (const Point &b) const{
    return !(*this == b);
  }
};

int N,M,ip[MX][MX],op[MX][MX];
Point p(-1,-1), q; // p move q to ed
vector<Point> ans;
vector<Point> seq;
int bad[MX][MX];
Point prv[MX][MX];
Point que[MX*MX];
int vst[MX][MX];
int fr,bk;
int dir[8][2] = {{-1,0},{1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}};
vector<Point> path;

void BFS(Point ed){
//  printf("BFS %d %d -> %d %d\n", p.x, p.y, ed.x, ed.y);
  fr = bk = 0;
  _SZ(vst);
  que[bk++] = p;
  vst[p.x][p.y] = 1;
  while (fr < bk){
    Point u = que[fr++];
    for (int i=0; i<8; i++){
      int nx = u.x + dir[i][0];
      int ny = u.y + dir[i][1];
      if (nx < 1 || ny < 1 || nx > N || ny > M) continue;
      if (bad[nx][ny]) continue;
      if (q.x == nx && q.y == ny) continue;
      if (vst[nx][ny]) continue;
      que[bk++] = Point(nx,ny);
      prv[nx][ny] = u;
      vst[nx][ny] = 1;
    }
  //  if (vst[ed.x][ed.y]) break;
  }
  assert(vst[ed.x][ed.y] == 1);
  path.clear();
  Point cur = ed;
  while (cur != p){
    path._PB(cur);
    cur = prv[cur.x][cur.y];
  }
  reverse(path.begin(),path.end());
}
void move(Point a){
  if (ans.size()){
    assert(a != ans.back());
  }
  ans._PB(a);
  swap(ip[a.x][a.y],ip[p.x][p.y]);
  p = a;
}
void solve(Point ed){
//  if (ip[ed.x][ed.y] == op[ed.x][ed.y]) return ;
  /*
  printf("solving %d %d\n", ed.x, ed.y);
  for (int i=1; i<=N; i++){
    for (int j=1; j<=M; j++)
      printf("%d ", bad[i][j]);
    puts("");
  }
  printf("st (%d, %d)\n", p.x, p.y);
  */
  q = Point(-1,-1);
  for (int i=1; i<=N && q.x==-1; i++){
    for (int j=1; j<=M && q.x==-1; j++){
      if (bad[i][j]) continue;
      if (p.x == i && p.y == j) continue;
      if (ip[i][j] == op[ed.x][ed.y])
        q = Point(i,j);
    }
  }
//  printf("tar (%d, %d)\n", q.x, q.y);
  int dx=1;
  int dy=1;
  if (ed.x < q.x) dx = -1;
  if (ed.y < q.y) dy = -1;
  while (q != ed){
    if (q.x != ed.x && !bad[q.x+dx][q.y]){
      BFS(Point(q.x+dx,q.y));
      for (auto i : path)
        move(i);
      Point tmp = p;
      move(q);
      q = tmp;
    } else if (q.y != ed.y && !bad[q.x][q.y+dy]){
      BFS(Point(q.x,q.y+dy));
      for (auto i : path)
        move(i);
      Point tmp = p;
      move(q);
      q = tmp;
    } else {
      assert(false);
    }
  }
}
void solve_seq(){
  for (auto v : seq){
//    printf("solving %d %d\n", v.x , v.y);
    q = Point(-1,-1);
    /*
    BFS(Point(2,2));
    for (auto i : path)
      move(i);
      */
    solve(v);
    bad[v.x][v.y] = 1;
  }
}
void solve22(){
  if (p != Point(1,1)){
    q = Point(-1,-1);
    BFS(Point(1,1));
    for (auto i : path){
      move(i);
    }
  }
  if (ip[2][2] != op[2][2]){
    if (ip[1][2] == op[2][2]){
      move(Point(2,2));
      move(Point(1,2));
    } else if (ip[2][1] == op[2][2]){
      move(Point(2,2));
      move(Point(2,1));
    }
  }
  if (p != Point(1,1)){
    move(Point(1,1));
  }
  if (ip[1][2] != op[1][2]){
    move(Point(2,1));
    move(Point(1,2));
  }
  if (p != Point(1,1)){
    move(Point(1,1));
  }
}
int main()
{
  int c1[MX*MX] = {0};
  int c2[MX*MX] = {0};
  scanf("%d%d", &N, &M);
  for (int i=1; i<=N; i++){
    for (int j=1; j<=M; j++){
      scanf("%d", &ip[i][j]);
      c1[ip[i][j]]++;
    }
  }
  for (int i=1; i<=N; i++){
    for (int j=1; j<=M; j++){
      scanf("%d", &op[i][j]);
      c2[op[i][j]]++;
    }
  }
  for (int i=1; i<MX*MX; i++){
    if (c1[i] != c2[i]){
      puts("-1");
      return 0;
    }
  }
  if (N == 1){
    int sy = -1;
    int ey = -1;
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j]){
        if (sy == -1){
          sy = j;
        }
        ey = j;
      }
    }
    if (sy == -1){
      puts("0");
      puts("1 1");
      return 0;
    }
    int fail=0;
    // check sy -> ey
    for (int j=sy; j<ey; j++)
      swap(ip[1][j],ip[1][j+1]);
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j])
        fail = 1;
    }
    if (!fail){
      printf("%d\n", ey-sy);
      for (int j=sy; j<=ey; j++)
        printf("%d %d\n", 1, j);
      return 0;
    }
    for (int j=ey; j>sy; j--)
      swap(ip[1][j],ip[1][j-1]);
    // check ey -> sy
    fail = 0;
    for (int j=ey; j>sy; j--)
      swap(ip[1][j],ip[1][j-1]);
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j])
        fail = 1;
    }
    if (!fail){
      printf("%d\n", ey-sy);
      for (int j=ey; j>=sy; j--)
        printf("%d %d\n", 1, j);
    } else {
      puts("-1");
    }
    return 0;
  } else if (M == 1){
    int sx = -1;
    int ex = -1;
    for (int i=1; i<=N; i++){
      if (ip[i][1] != op[i][1]){
        if (sx == -1){
          sx = i;
        }
        ex = i;
      }
    }
    if (sx == -1){
      puts("0");
      puts("1 1");
      return 0;
    }
    int fail = 0;
    // check sx -> ex
    for (int i=sx; i<ex; i++)
      swap(ip[i][1],ip[i+1][1]);
    for (int i=1; i<=N; i++)
      if (ip[i][1] != op[i][1])
        fail = 1;
    if (!fail){
      printf("%d\n", ex-sx);
      for (int i=sx; i<=ex; i++)
        printf("%d %d\n", i, 1);
      return 0;
    }
    for (int i=ex; i>sx; i--)
      swap(ip[i][1],ip[i-1][1]);
    // check ex -> sx
    for (int i=ex; i>sx; i--)
      swap(ip[i][1], ip[i-1][1]);
    fail = 0;
    for (int i=1; i<=N; i++)
      if (ip[i][1] != op[i][1])
        fail = 1;
    if (!fail){
      printf("%d\n", ex-sx);
      for (int i=ex; i>=sx; i--)
        printf("%d %d\n", i, 1);
    } else {
      puts("-1");
    }
    return 0;
  } else {
    p = Point(-1,-1);
    for (int i=1; i<=N && p.x == -1; i++){
      for (int j=1; j<=M && p.x == -1; j++){
        if (ip[i][j] == op[1][1]){
          p = Point(i,j);
        }
      }
    }
    int x = p.x;
    int y = p.y;
//    printf("st = (%d, %d)\n", x, y);
    for (int j=M; j>2; j--){
      for (int i=N; i>=1; i--){
        seq._PB(Point(i,j));
      }
    }
    for (int i=N; i>2; i--){
      seq._PB(Point(i,2));
      seq._PB(Point(i,1));
    }
    _SZ(bad);
    /*
    puts("seq : ");
    for (auto i : seq)
      printf("%d %d\n", i.x, i.y);
   puts("==");
    */
    solve_seq();

    for (int i=1; i<=N; i++){
      for (int j=1; j<=M; j++){
        //printf("%d ", ip[i][j]);
        if (i>2 && j>2 && ip[i][j] != op[i][j]){
          assert(false);
        }
      }
     //puts("");
    }

    solve22();
    for (int i=1; i<=N; i++){
      for (int j=1; j<=M; j++){
        if (ip[i][j] != op[i][j]){
          assert(false);
          //printf("fail @ %d %d\n", i, j);
        }
      }
    }
    assert(ans.size() <= 1000000);
    printf("%d\n", (int)ans.size());
    printf("%d %d\n", x, y);
    for (auto i : ans)
      printf("%d %d\n", i.x, i.y);
  }

  return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define _SZ(n) memset((n),0,sizeof(n))
#define _SMO(n) memset((n),-1,sizeof(n))
#define _MC(n,m) memcpy((n),(m),sizeof(n))
#define _F first
#define _S second
#define _MP make_pair
#define _PB push_back
#define FOR(x,y) for(__typeof(y.begin())x=y.begin();x!=y.end();x++)
#define IOS ios_base::sync_with_stdio(0)
#ifdef ONLINE_JUDGE
#define FILEIO(name) \
  freopen(name".in", "r", stdin); \
  freopen(name".out", "w", stdout);
#else
#define FILEIO(name)
#endif
// Let's Fight!

const int MX = 35;

struct Point{
  int x,y;
  Point () {}
  Point (int _x, int _y) : x(_x), y(_y) {}
  bool operator == (const Point &b) const{
    return x == b.x && y == b.y;
  }
  bool operator != (const Point &b) const{
    return !(*this == b);
  }
};

int N,M,ip[MX][MX],op[MX][MX];
Point p(-1,-1), q; // p move q to ed
vector<Point> ans;
vector<Point> seq;
int bad[MX][MX];
Point prv[MX][MX];
Point que[MX*MX];
int vst[MX][MX];
int fr,bk;
int dir[8][2] = {{-1,0},{1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}};
vector<Point> path;

void BFS(Point ed){
//  printf("BFS %d %d -> %d %d\n", p.x, p.y, ed.x, ed.y);
  fr = bk = 0;
  _SZ(vst);
  que[bk++] = p;
  vst[p.x][p.y] = 1;
  while (fr < bk){
    Point u = que[fr++];
    for (int i=0; i<8; i++){
      int nx = u.x + dir[i][0];
      int ny = u.y + dir[i][1];
      if (nx < 1 || ny < 1 || nx > N || ny > M) continue;
      if (bad[nx][ny]) continue;
      if (q.x == nx && q.y == ny) continue;
      if (vst[nx][ny]) continue;
      que[bk++] = Point(nx,ny);
      prv[nx][ny] = u;
      vst[nx][ny] = 1;
    }
    if (vst[ed.x][ed.y]) break;
  }
  assert(vst[ed.x][ed.y] == 1);
  path.clear();
  Point cur = ed;
  while (cur != p){
    path._PB(cur);
    cur = prv[cur.x][cur.y];
  }
  reverse(path.begin(),path.end());
}
void move(Point a){
  ans._PB(a);
  swap(ip[a.x][a.y],ip[p.x][p.y]);
  p = a;
}
void solve(Point ed){
  if (ip[ed.x][ed.y] == op[ed.x][ed.y]) return ;
  q = Point(-1,-1);
  for (int i=1; i<=N && q.x==-1; i++){
    for (int j=1; j<=M && q.x==-1; j++){
      if (bad[i][j]) continue;
      if (p.x == i && p.y == j) continue;
      if (ip[i][j] == op[ed.x][ed.y])
        q = Point(i,j);
    }
  }
  while (q.x != ed.x){
    while (q.x > ed.x){
      BFS(Point(q.x-1,q.y));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
    while (q.x < ed.x){
      BFS(Point(q.x+1,q.y));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
  }
  while (q.y != ed.y){
    while (q.y > ed.y){
      BFS(Point(q.x,q.y-1));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
    while (q.y < ed.y){
      BFS(Point(q.x,q.y+1));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
  }
}
void solve_seq(){
  for (auto v : seq){
//    printf("solving %d %d\n", v.x , v.y);
    solve(v);
    bad[v.x][v.y] = 1;
  }
}
void solve22(){
  if (p != Point(1,1)){
    move(Point(1,1));
  }
  if (ip[2][2] != op[2][2]){
    if (ip[1][2] == op[2][2]){
      move(Point(2,2));
      move(Point(1,2));
    } else if (ip[2][1] == op[2][2]){
      move(Point(2,2));
      move(Point(2,1));
    }
  }
  if (p != Point(1,1)){
    move(Point(1,1));
  }
  if (ip[1][2] != op[1][2]){
    move(Point(2,1));
    move(Point(1,2));
  }
  if (p != Point(1,1)){
    move(Point(1,1));
  }
}
int main()
{
  int c1[MX*MX] = {0};
  int c2[MX*MX] = {0};
  scanf("%d%d", &N, &M);
  for (int i=1; i<=N; i++){
    for (int j=1; j<=M; j++){
      scanf("%d", &ip[i][j]);
      c1[ip[i][j]]++;
    }
  }
  for (int i=1; i<=N; i++){
    for (int j=1; j<=M; j++){
      scanf("%d", &op[i][j]);
      c2[op[i][j]]++;
    }
  }
  for (int i=1; i<MX*MX; i++){
    if (c1[i] != c2[i]){
      puts("-1");
      return 0;
    }
  }
  if (N == 1){
    int sy = -1;
    int ey = -1;
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j]){
        if (sy == -1){
          sy = j;
        }
        ey = j;
      }
    }
    if (sy == -1){
      puts("0");
      puts("1 1");
      return 0;
    }
    int fail=0;
    // check sy -> ey
    for (int j=sy; j<ey; j++)
      swap(ip[1][j],ip[1][j+1]);
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j])
        fail = 1;
    }
    if (!fail){
      printf("%d\n", ey-sy);
      for (int j=sy; j<=ey; j++)
        printf("%d %d\n", 1, j);
      return 0;
    }
    for (int j=ey; j>sy; j--)
      swap(ip[1][j],ip[1][j-1]);
    // check ey -> sy
    fail = 0;
    for (int j=ey; j>sy; j--)
      swap(ip[1][j],ip[1][j-1]);
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j])
        fail = 1;
    }
    if (!fail){
      printf("%d\n", ey-sy);
      for (int j=ey; j>=sy; j--)
        printf("%d %d\n", 1, j);
    } else {
      puts("-1");
    }
    return 0;
  } else if (M == 1){
    int sx = -1;
    int ex = -1;
    for (int i=1; i<=N; i++){
      if (ip[i][1] != op[i][1]){
        if (sx == -1){
          sx = i;
        }
        ex = i;
      }
    }
    if (sx == -1){
      puts("0");
      puts("1 1");
      return 0;
    }
    int fail = 0;
    // check sx -> ex
    for (int i=sx; i<ex; i++)
      swap(ip[i][1],ip[i+1][1]);
    for (int i=1; i<=N; i++)
      if (ip[i][1] != op[i][1])
        fail = 1;
    if (!fail){
      printf("%d\n", ex-sx);
      for (int i=sx; i<=ex; i++)
        printf("%d %d\n", i, 1);
      return 0;
    }
    for (int i=ex; i>sx; i--)
      swap(ip[i][1],ip[i-1][1]);
    // check ex -> sx
    for (int i=ex; i>sx; i--)
      swap(ip[i][1], ip[i-1][1]);
    fail = 0;
    for (int i=1; i<=N; i++)
      if (ip[i][1] != op[i][1])
        fail = 1;
    if (!fail){
      printf("%d\n", ex-sx);
      for (int i=ex; i>=sx; i--)
        printf("%d %d\n", i, 1);
    } else {
      puts("-1");
    }
  } else {
    p = Point(-1,-1);
    for (int i=1; i<=N && p.x == -1; i++){
      for (int j=1; j<=M && p.x == -1; j++){
        if (ip[i][j] == op[1][1]){
          p = Point(i,j);
        }
      }
    }
    int x = p.x;
    int y = p.y;
//    printf("st = (%d, %d)\n", x, y);
    for (int j=M; j>2; j--){
      for (int i=N; i>=1; i--){
        seq._PB(Point(i,j));
      }
    }
    for (int i=N; i>2; i--){
      seq._PB(Point(i,2));
      seq._PB(Point(i,1));
    }
    _SZ(bad);
    /*
    puts("seq : ");
    for (auto i : seq)
      printf("%d %d\n", i.x, i.y);
    puts("==");
    */
    solve_seq();

    for (int i=1; i<=N; i++){
      for (int j=1; j<=M; j++){
        printf("%d ", ip[i][j]);
        if (i>2 && j>2 && ip[i][j] != op[i][j]){
          assert(false);
          puts("FAIL QAQ");
        }
      }
      puts("");
    }

    solve22();
    for (int i=1; i<=N; i++){
      for (int j=1; j<=M; j++){
        if (ip[i][j] != op[i][j]){
          printf("fail @ %d %d\n", i, j);
          exit(0);
        }
      }
    }
    assert(ans.size() <= 1000000);
    printf("%d\n", (int)ans.size());
    printf("%d %d\n", x, y);
    for (auto i : ans)
      printf("%d %d\n", i.x, i.y);
  }

  return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define _SZ(n) memset((n),0,sizeof(n))
#define _SMO(n) memset((n),-1,sizeof(n))
#define _MC(n,m) memcpy((n),(m),sizeof(n))
#define _F first
#define _S second
#define _MP make_pair
#define _PB push_back
#define FOR(x,y) for(__typeof(y.begin())x=y.begin();x!=y.end();x++)
#define IOS ios_base::sync_with_stdio(0)
#ifdef ONLINE_JUDGE
#define FILEIO(name) \
  freopen(name".in", "r", stdin); \
  freopen(name".out", "w", stdout);
#else
#define FILEIO(name)
#endif
// Let's Fight!

const int MX = 35;

struct Point{
  int x,y;
  Point () {}
  Point (int _x, int _y) : x(_x), y(_y) {}
  bool operator == (const Point &b) const{
    return x == b.x && y == b.y;
  }
  bool operator != (const Point &b) const{
    return !(*this == b);
  }
};

int N,M,ip[MX][MX],op[MX][MX];
Point p(-1,-1), q; // p move q to ed
vector<Point> ans;
vector<Point> seq;
int bad[MX][MX];
Point prv[MX][MX];
Point que[MX*MX];
int vst[MX][MX];
int fr,bk;
int dir[8][2] = {{-1,0},{1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}};
vector<Point> path;

void BFS(Point ed){
//  printf("BFS %d %d -> %d %d\n", p.x, p.y, ed.x, ed.y);
  fr = bk = 0;
  _SZ(vst);
  que[bk++] = p;
  vst[p.x][p.y] = 1;
  while (fr < bk){
    Point u = que[fr++];
    for (int i=0; i<8; i++){
      int nx = u.x + dir[i][0];
      int ny = u.y + dir[i][1];
      if (nx < 1 || ny < 1 || nx > N || ny > M) continue;
      if (bad[nx][ny]) continue;
      if (q.x == nx && q.y == ny) continue;
      if (vst[nx][ny]) continue;
      que[bk++] = Point(nx,ny);
      prv[nx][ny] = u;
      vst[nx][ny] = 1;
    }
    if (vst[ed.x][ed.y]) break;
  }
  assert(vst[ed.x][ed.y] == 1);
  path.clear();
  Point cur = ed;
  while (cur != p){
    path._PB(cur);
    cur = prv[cur.x][cur.y];
  }
  reverse(path.begin(),path.end());
}
void move(Point a){
  if (ans.size()){
    assert(a != ans.back());
  }
  ans._PB(a);
  swap(ip[a.x][a.y],ip[p.x][p.y]);
  p = a;
}
void solve(Point ed){
  q = Point(-1,-1);
  for (int i=1; i<=N && q.x==-1; i++){
    for (int j=1; j<=M && q.x==-1; j++){
      if (bad[i][j]) continue;
      if (p.x == i && p.y == j) continue;
      if (ip[i][j] == op[ed.x][ed.y])
        q = Point(i,j);
    }
  }
  int dx=1;
  int dy=1;
  if (ed.x < q.x) dx = -1;
  if (ed.y < q.y) dy = -1;
  while (q != ed){
    if (q.x != ed.x && q.y != ed.y && !bad[q.x+dx][q.y+dy]){
      BFS(Point(q.x+dx,q.y+dy));
    } else if (q.x != ed.x && !bad[q.x+dx][q.y]){
      BFS(Point(q.x+dx,q.y));
    } else if (q.y != ed.y && !bad[q.x][q.y+dy]){
      BFS(Point(q.x,q.y+dy));
    } else {
      assert(false);
    }
      for (auto i : path)
        move(i);
      Point tmp = p;
      move(q);
      q = tmp;
  }
}
void solve_seq(){
  for (auto v : seq){
    solve(v);
    bad[v.x][v.y] = 1;
  }
}
void solve22(){
  if (p != Point(1,1)){
    q = Point(-1,-1);
    BFS(Point(1,1));
    for (auto i : path){
      move(i);
    }
  }
  if (ip[2][2] != op[2][2]){
    if (ip[1][2] == op[2][2]){
      move(Point(2,2));
      move(Point(1,2));
    } else if (ip[2][1] == op[2][2]){
      move(Point(2,2));
      move(Point(2,1));
    }
  }
  if (p != Point(1,1)){
    move(Point(1,1));
  }
  if (ip[1][2] != op[1][2]){
    move(Point(2,1));
    move(Point(1,2));
  }
  if (p != Point(1,1)){
    move(Point(1,1));
  }
}
bool check(Point st, Point ed){
  int dx = 0;
  int dy = 0;
  if (ed.x < st.x) dx = -1;
  if (ed.x > st.x) dx = 1;
  if (ed.y < st.y) dy = -1;
  if (ed.y > st.y) dy = 1;
  int tp[MX][MX];
  for (int i=0; i<MX; i++)
    for (int j=0; j<MX; j++)
      tp[i][j] = ip[i][j];
  ans.clear();
  while (st != ed){
    ans._PB(st);
    swap(tp[st.x][st.y],tp[st.x+dx][st.y+dy]);
    st.x += dx;
    st.y += dy;
  }
  ans._PB(ed);
  int fail=0;
  for (int i=1; i<=N && !fail; i++)
    for (int j=1; j<=M && !fail; j++)
      if (tp[i][j] != op[i][j])
        fail = 1;
  return !fail;
}
int main()
{
  int c1[MX*MX] = {0};
  int c2[MX*MX] = {0};
  scanf("%d%d", &N, &M);
  for (int i=1; i<=N; i++){
    for (int j=1; j<=M; j++){
      scanf("%d", &ip[i][j]);
      c1[ip[i][j]]++;
    }
  }
  for (int i=1; i<=N; i++){
    for (int j=1; j<=M; j++){
      scanf("%d", &op[i][j]);
      c2[op[i][j]]++;
    }
  }
  for (int i=1; i<MX*MX; i++){
    if (c1[i] != c2[i]){
      puts("-1");
      return 0;
    }
  }
  if (N == 1 || M == 1){
    vector<Point> pt;
    for (int i=1; i<=N; i++)
      for (int j=1; j<=M; j++)
        pt._PB(Point(i,j));
    int n = pt.size();
    int ok = 0;
    for (int i=0; i<n && !ok; i++){
      for (int j=0; j<n && !ok; j++){
        if (i == j) continue;
        if (check(pt[i],pt[j])){
          ok = 1;
        }
      }
    }
    if (ok){
      printf("%d\n", (int)ans.size()-1);
      for (auto i : ans)
        printf("%d %d\n", i.x, i.y);
    } else {
      puts("-1");
    }
  } else {
    p = Point(-1,-1);
    for (int i=1; i<=N && p.x == -1; i++){
      for (int j=1; j<=M && p.x == -1; j++){
        if (ip[i][j] == op[1][1]){
          p = Point(i,j);
        }
      }
    }
    int x = p.x;
    int y = p.y;
    for (int j=M; j>2; j--){
      for (int i=N; i>=1; i--){
        seq._PB(Point(i,j));
      }
    }
    for (int i=N; i>2; i--){
      seq._PB(Point(i,2));
      seq._PB(Point(i,1));
    }
    _SZ(bad);
    solve_seq();

    for (int i=1; i<=N; i++){
      for (int j=1; j<=M; j++){
        if (i>2 && j>2 && ip[i][j] != op[i][j]){
          assert(false);
        }
      }
    }

    solve22();
    for (int i=1; i<=N; i++){
      for (int j=1; j<=M; j++){
        if (ip[i][j] != op[i][j]){
          assert(false);
        }
      }
    }
    assert(ans.size() <= 1000000);
    printf("%d\n", (int)ans.size());
    printf("%d %d\n", x, y);
    for (auto i : ans)
      printf("%d %d\n", i.x, i.y);
  }

  return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define _SZ(n) memset((n),0,sizeof(n))
#define _SMO(n) memset((n),-1,sizeof(n))
#define _MC(n,m) memcpy((n),(m),sizeof(n))
#define _F first
#define _S second
#define _MP make_pair
#define _PB push_back
#define FOR(x,y) for(__typeof(y.begin())x=y.begin();x!=y.end();x++)
#define IOS ios_base::sync_with_stdio(0)
#ifdef ONLINE_JUDGE
#define FILEIO(name) \
  freopen(name".in", "r", stdin); \
  freopen(name".out", "w", stdout);
#else
#define FILEIO(name)
#endif
// Let's Fight!

const int MX = 35;

struct Point{
  int x,y;
  Point () {}
  Point (int _x, int _y) : x(_x), y(_y) {}
  bool operator == (const Point &b) const{
    return x == b.x && y == b.y;
  }
  bool operator != (const Point &b) const{
    return !(*this == b);
  }
};

int N,M,ip[MX][MX],op[MX][MX];
Point p(-1,-1), q; // p move q to ed
vector<Point> ans;
vector<Point> seq;
int bad[MX][MX];
Point prv[MX][MX];
Point que[MX*MX];
int vst[MX][MX];
int fr,bk;
int dir[8][2] = {{-1,0},{1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}};
vector<Point> path;

void BFS(Point ed){
//  printf("BFS %d %d -> %d %d\n", p.x, p.y, ed.x, ed.y);
  fr = bk = 0;
  _SZ(vst);
  que[bk++] = p;
  vst[p.x][p.y] = 1;
  while (fr < bk){
    Point u = que[fr++];
    for (int i=0; i<8; i++){
      int nx = u.x + dir[i][0];
      int ny = u.y + dir[i][1];
      if (nx < 1 || ny < 1 || nx > N || ny > M) continue;
      if (bad[nx][ny]) continue;
      if (q.x == nx && q.y == ny) continue;
      if (vst[nx][ny]) continue;
      que[bk++] = Point(nx,ny);
      prv[nx][ny] = u;
      vst[nx][ny] = 1;
    }
    if (vst[ed.x][ed.y]) break;
  }
  assert(vst[ed.x][ed.y] == 1);
  path.clear();
  Point cur = ed;
  while (cur != p){
    path._PB(cur);
    cur = prv[cur.x][cur.y];
  }
  reverse(path.begin(),path.end());
}
void move(Point a){
  ans._PB(a);
  swap(ip[a.x][a.y],ip[p.x][p.y]);
  p = a;
}
void solve(Point ed){
  if (ip[ed.x][ed.y] == op[ed.x][ed.y]) return ;
  q = Point(-1,-1);
  for (int i=1; i<=N && q.x==-1; i++){
    for (int j=1; j<=M && q.x==-1; j++){
      if (bad[i][j]) continue;
      if (p.x == i && p.y == j) continue;
      if (ip[i][j] == op[ed.x][ed.y])
        q = Point(i,j);
    }
  }
  while (q.x != ed.x){
    while (q.x > ed.x){
      BFS(Point(q.x-1,q.y));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
    while (q.x < ed.x){
      BFS(Point(q.x+1,q.y));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
  }
  while (q.y != ed.y){
    while (q.y > ed.y){
      BFS(Point(q.x,q.y-1));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
    while (q.y < ed.y){
      BFS(Point(q.x,q.y+1));
      for (auto i : path){
        move(i);
      }
      Point tmp = p;
      move(q);
      q = tmp;
    }
  }
}
void solve_seq(){
  for (auto v : seq){
//    printf("solving %d %d\n", v.x , v.y);
    solve(v);
    bad[v.x][v.y] = 1;
  }
}
void solve22(){
  if (p != Point(1,1)){
    move(Point(1,1));
  }
  if (ip[2][2] != op[2][2]){
    if (ip[1][2] == op[2][2]){
      move(Point(2,2));
      move(Point(1,2));
    } else if (ip[2][1] == op[2][2]){
      move(Point(2,2));
      move(Point(2,1));
    }
  }
  if (p != Point(1,1)){
    move(Point(1,1));
  }
  if (ip[1][2] != op[1][2]){
    move(Point(2,1));
    move(Point(1,2));
  }
  if (p != Point(1,1)){
    move(Point(1,1));
  }
}
int main()
{
  int c1[MX*MX] = {0};
  int c2[MX*MX] = {0};
  scanf("%d%d", &N, &M);
  for (int i=1; i<=N; i++){
    for (int j=1; j<=M; j++){
      scanf("%d", &ip[i][j]);
      c1[ip[i][j]]++;
    }
  }
  for (int i=1; i<=N; i++){
    for (int j=1; j<=M; j++){
      scanf("%d", &op[i][j]);
      c2[op[i][j]]++;
    }
  }
  for (int i=1; i<MX*MX; i++){
    if (c1[i] != c2[i]){
      puts("-1");
      return 0;
    }
  }
  if (N == 1){
    int sy = -1;
    int ey = -1;
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j]){
        if (sy == -1){
          sy = j;
        }
        ey = j;
      }
    }
    if (sy == -1){
      puts("0");
      return 0;
    }
    int fail=0;
    // check sy -> ey
    for (int j=sy; j<ey; j++)
      swap(ip[1][j],ip[1][j+1]);
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j])
        fail = 1;
    }
    if (!fail){
      printf("%d\n", ey-sy);
      for (int j=sy; j<=ey; j++)
        printf("%d %d\n", 1, j);
      return 0;
    }
    for (int j=ey; j>sy; j--)
      swap(ip[1][j],ip[1][j-1]);
    // check ey -> sy
    fail = 0;
    for (int j=ey; j>sy; j--)
      swap(ip[1][j],ip[1][j-1]);
    for (int j=1; j<=M; j++){
      if (ip[1][j] != op[1][j])
        fail = 1;
    }
    if (!fail){
      printf("%d\n", ey-sy);
      for (int j=ey; j>=sy; j--)
        printf("%d %d\n", 1, j);
    } else {
      puts("-1");
    }
    return 0;
  } else if (M == 1){
    int sx = -1;
    int ex = -1;
    for (int i=1; i<=N; i++){
      if (ip[i][1] != op[i][1]){
        if (sx == -1){
          sx = i;
        }
        ex = i;
      }
    }
    if (sx == -1){
      puts("0");
      return 0;
    }
    int fail = 0;
    // check sx -> ex
    for (int i=sx; i<ex; i++)
      swap(ip[i][1],ip[i+1][1]);
    for (int i=1; i<=N; i++)
      if (ip[i][1] != op[i][1])
        fail = 1;
    if (!fail){
      printf("%d\n", ex-sx);
      for (int i=sx; i<=ex; i++)
        printf("%d %d\n", i, 1);
      return 0;
    }
    for (int i=ex; i>sx; i--)
      swap(ip[i][1],ip[i-1][1]);
    // check ex -> sx
    for (int i=ex; i>sx; i--)
      swap(ip[i][1], ip[i-1][1]);
    fail = 0;
    for (int i=1; i<=N; i++)
      if (ip[i][1] != op[i][1])
        fail = 1;
    if (!fail){
      printf("%d\n", ex-sx);
      for (int i=ex; i>=sx; i--)
        printf("%d %d\n", i, 1);
    } else {
      puts("-1");
    }
  } else {
    p = Point(-1,-1);
    for (int i=1; i<=N && p.x == -1; i++){
      for (int j=1; j<=M && p.x == -1; j++){
        if (ip[i][j] == op[1][1]){
          p = Point(i,j);
        }
      }
    }
    int x = p.x;
    int y = p.y;
//    printf("st = (%d, %d)\n", x, y);
    for (int j=M; j>2; j--){
      for (int i=N; i>=1; i--){
        seq._PB(Point(i,j));
      }
    }
    for (int i=N; i>2; i--){
      seq._PB(Point(i,2));
      seq._PB(Point(i,1));
    }
    _SZ(bad);
    /*
    puts("seq : ");
    for (auto i : seq)
      printf("%d %d\n", i.x, i.y);
    puts("==");
    */
    solve_seq();
    /*
    for (int i=1; i<=N; i++){
      for (int j=1; j<=M; j++){
        printf("%d ", ip[i][j]);
        if (i>2 && j>2 && ip[i][j] != op[i][j]){
          puts("FAIL QAQ");
        }
      }
      puts("");
    }
    */
    solve22();
    for (int i=1; i<=N; i++){
      for (int j=1; j<=M; j++){
        if (ip[i][j] != op[i][j]){
          printf("fail @ %d %d\n", i, j);
          exit(0);
        }
      }
    }
    assert(ans.size() <= 1000000);
    printf("%d\n", (int)ans.size());
    printf("%d %d\n", x, y);
    for (auto i : ans)
      printf("%d %d\n", i.x, i.y);
  }

  return 0;
}