#pragma GCC optimize("Ofast,unroll-loops")
#pragma GCC target("avx,avx2,tune=native")

#include <iostream>
#include <vector>
#include <set>
#include <cmath>
#include <numeric>
#include <map>
#include <cassert>
#include <algorithm>
#include <random>
#include <stack>

using namespace std;

#define int long long
#define se second
#define fi first

vector<vector<pair<int, pair<int, int>>>> adj;
vector<vector<int>> adj2;
vector<bool> used2;
vector<int> used;
vector<stack<pair<int, int>>> p;
int d = 0, sz, start, last;

int dfs2(int v)
{
	used2[v] = 1;
	int ans = 1;
	for (int i = 0; i < adj2[v].size(); ++i)
	{
		if (used2[adj2[v][i]]) continue;
		ans += dfs2(adj2[v][i]);
	}
	return ans;
}

int dfs(int v, pair<int, int> pr)
{
	used[v]++;
	p[v].push(pr);
	if (used[v] == adj[v].size()) d++;
	for (int i = 0; i < adj[v].size(); ++i)
	{
		if (adj[v][i].first == start && d == sz)
		{
			last = v;
			return 1;
		}
		if (adj[v][i].se.se) continue;
		adj[v][i].se.se = 1;
		if (dfs(adj[v][i].fi, { v, adj[v][i].second.fi })) return 1;
		adj[v][i].se.se = 0;
	}
	p[v].pop();
	used[v]--;
	if (used[v] != adj[v].size()) --d;
	return 0;
}

signed main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int n, m, c;
	cin >> n >> m;
	vector<int> a(m * n);
	adj.resize(n + m);
	adj2.resize(n + m);
	used.resize(n + m);
	used2.resize(n + m);
	p.resize(n + m);
	for (auto& i : a)
	{
		cin >> i;
		--i;
	}
	vector<pair<int, int>> res;
	vector<vector<vector<int>>> out(n, vector<vector<int>>(m));
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < m; ++j)
		{
			out[i][a[i * m + j]].push_back(i * m + j);
		}
		for (int j = 0; j < m; ++j)
		{
			if (out[i][j].size() > 1)
			{
				for (int k = 1; k < out[i][j].size(); ++k)
				{
					adj[i].push_back({ n + j, {out[i][j][k] + 1, 0} });
					adj2[i].push_back(n + j);
					adj2[n + j].push_back(i);
				}
			}
			else if (out[i][j].size() == 0)
			{
				adj[n + j].push_back({ i, {-1, 0} });
				adj2[i].push_back(n + j);
				adj2[n + j].push_back(i);
			}
		}
	}
	for (int i = 0; i < n; ++i)
	{
		if (used[i] == adj[i].size()) continue;
		sz = dfs2(i);
		start = i;
		d = 0;
		dfs(i, { -1, -1 });
		vector<int> ans;
		pair<int, int> cur = { last, -1 };
		while (cur.fi != -1)
		{
			if (cur.second != -1) ans.push_back(cur.se);
			pair<int, int> t = p[cur.fi].top();
			p[cur.fi].pop();
			cur = t;
		}
		res.push_back({ ans[0], m * n + 1 });
		for (int i = 1; i < ans.size(); ++i) res.push_back({ ans[i], ans[i - 1] });
		res.push_back({ m * n + 1, ans[ans.size() - 1] });
	}
	cout << res.size() << '\n';
	for (int i = 0; i < res.size(); ++i) cout << res[i].first << " " << res[i].second << '\n';
	return 0;
}
