#include <bits/stdc++.h>

using namespace std;

int n, m;
vector< vector<int> > a;

//vector< vector< vector<int> > > cnt0;

vector< set< pair<int,int> > > cnt; // n ( count, el )
vector< vector< vector<int> > > pos; // n m pos
vector< set< pair<int,int> > > cnte; // m set pair cnt row

vector< pair<int,int> > ans;

int gpos ( int i, int j )
{
    return i*m + j;
}

int main ()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    cin >> n >> m;

    a.assign( n, vector<int>(m) );

    for ( auto& v : a )
    for ( auto& el : v )
    {
        cin >> el;
        el--;
    }

    cnt.assign( n, set< pair<int,int> >() );
    pos.assign( n, vector< vector<int> >( m ) );
    cnte.assign( m, set< pair<int,int> >() );

    for ( int i=0; i<n; i++ )
    for ( int j=0; j<m; j++ )
        pos[i][ a[i][j] ].push_back( j );

    for ( int i=0; i<n; i++ )
    for ( int j=0; j<m; j++ )
    {
        cnt[i].insert({ pos[i][j].size(), j });
        cnte[j].insert({ pos[i][j].size(), i });
    }

    for ( int i=0; i<n; i++ )
    while ( cnt[i].size() && (--cnt[i].end())->first > 1 )
    {
        int w = (--cnt[i].end())->second;

        int cpos = n*m;

        cnte[w].erase({ pos[i][w].size(), i });

        ans.push_back({ gpos(i, pos[i][w].back() ), cpos });
        cpos = gpos(i, pos[i][w].back() );
        pos[i][w].pop_back();

        cnt[i].erase( --cnt[i].end() );
        cnt[i].insert({ pos[i][w].size(), w });

        cnte[w].insert({ pos[i][w].size(), i });

        if ( cnt[i].begin()->first > 0 )
            continue;

        w = cnt[i].begin()->second;

        int grow = i;

        while ( cnte[w].size() && (--cnte[w].end())->first > 1 )
        {
            int ccnt = (--cnte[w].end())->first;
            int crow = (--cnte[w].end())->second;

            ans.push_back({ gpos(crow, pos[crow][w].back()), gpos(grow, cpos) });

            cnt[grow].erase({ pos[grow][w].size(), w });
            cnte[w].erase({ pos[grow][w].size(), grow });

            pos[grow][w].push_back( cpos );

            cnte[w].insert({ pos[grow][w].size(), grow });
            cnt[grow].insert({ pos[grow][w].size(), w });

            //

            cnt[crow].erase({ pos[crow][w].size(), w });
            cnte[w].erase({ pos[crow][w].size(), crow });

            int newpos = pos[crow][w].back();
            pos[crow][w].pop_back();

            cnte[w].insert({ pos[crow][w].size(), crow });
            cnt[crow].insert({ pos[crow][w].size(), w });

            //

            cpos = newpos;
            grow = crow;

            w = cnt[grow].begin()->second;
        }

        ans.push_back({ gpos( grow, cpos ), n*m });

        cnt[grow].erase({ pos[grow][w].size(), w });
        cnte[w].erase({ pos[grow][w].size(), grow });

        pos[grow][w].push_back( cpos );

        cnte[w].insert({ pos[grow][w].size(), grow });
        cnt[grow].insert({ pos[grow][w].size(), w });
    }

    cout << ans.size() << '\n';

    for ( auto& [x,y] : ans )
        cout << x << ' ' << y << '\n';

    return 0;
}
