#include <iostream>
#include <vector>
#include <cmath>
#include <map>

using namespace std;

#define int long long

struct chunk {
    vector<int> count;
    vector<int> pos;

    bool isCorrect() {
        for (int i = 1; i < count.size(); i++) {
            if (count[i] == 0)
                return false;
        }
        return true;
    }

    int getNotHaveType() {
        for (int i = 1; i < count.size(); i++) {
            if (count[i] == 0) {
                return i;
            }
        }
    }

    int getElementById(int id) {
        for (int i = 0; i < pos.size(); i++)
            if (pos[i] == id)
                return i;
    }

    void set(int x, int elem) {
        if (pos[x] != -1) {
            cout << 11 / 0 << endl;
            return;
        }

        pos[x] = elem;
        count[elem]++;
    }

    void delete_(int x) {
        count[pos[x]]--;
        pos[x] = -1;
    }

    int getFree() {
        for (int i = 0; i < pos.size(); i++)
            if (pos[i] == -1)
                return i;
    }

};

signed main() {
    int n, m;
    cin >> n >> m;
    vector<chunk> v(n);
    for (int i = 0; i < n; i++) {
        v[i].count.resize(m + 1, 0);
        for (int j = 0; j < m; j++) {
            int x;
            cin >> x;
            v[i].pos.push_back(x);
            v[i].count[x]++;
        }
    }
    vector<string> ans;

    for (int i = 0; i < v.size(); i++) {
        if (v[i].isCorrect())
            continue;
        for (int j = 0; j < v[i].pos.size(); j++) {
            if (v[i].count[v[i].pos[j]] > 1) {
                int element = v[i].getElementById(v[i].pos[j]);
                v[i].delete_(j);
                ans.push_back(to_string(m * i + j + 1) +" " + to_string((n * m + 1)));
            }
        }
        break;
    }
    int pos = 0;
    while (true) {
        int lf = 0;
        for (int i = 0; i < v.size(); i++)
            lf += v[i].isCorrect();
        if (v.size() - lf <= 1) {
            break;
        }
        if (v[pos].isCorrect())
            pos++;

        int type = v[pos].getNotHaveType();
        for (int x = 0; x < v.size(); x++) {
            if (v[x].count[type] > 1) {
                int pos_ = v[x].getElementById(type);
                ans.push_back(to_string( m * x + pos_ + 1) +" " + to_string(m * pos + v[pos].getFree() + 1));
                v[x].delete_(pos_);
                v[pos].set(v[pos].getFree(), type);
                pos = x;
                break;
            }
        }
    }


    cout<<1 / 0<<endl;
    for (int i = 0; i < v.size(); i++) {
        if (!v[i].isCorrect()) {
            ans.push_back(to_string( n * m + 1) +" " + to_string(m * i + v[i].getFree() + 1));
        }
    }

    cout<<ans.size()<<endl;
    for(auto x: ans)
        cout<<x<<endl;
    return 0;
}
